...
Creating
...
a
...
Hello
...
World
...
JBI
...
Binding
...
Component
...
This
...
tutorial
...
describes
...
how
...
to
...
create
...
a
...
very
...
simple
...
Hello
...
World
...
style
...
of
...
JBI
...
binding
...
component.
...
This
...
tutorial
...
is
...
as
...
minimalistic
...
as
...
possible
...
so
...
as
...
to
...
focus
...
on
...
key
...
concepts
...
and
...
not
...
drown
...
in
...
details.
...
The
...
Hello
...
World
...
binding
...
component
...
will
...
respond
...
to
...
all
...
requests
...
with
...
the
...
message:
Panel | |||
---|---|---|---|
{panel}
|
The following sections will walk through the creation, packaging, testing and deployment of the Hello World binding component.
Prerequisites
- Maven 2.0.4
...
- or
...
- higher
- If you have never used Maven previously the Maven Getting Started Guide explains some valuable concepts surrounding Maven
- ServiceMix 3.1-incubating-SNAPSHOT
...
- or
...
- higher
...
- See
...
- the
...
...
...
- to
...
- grab
...
- a
...
- nightly
...
- build
...
- as
...
- ServiceMix
...
- 3.1
...
- has
...
- not
...
- yet
...
- been
...
- released
...
- A
...
- broadband
...
- internet
...
- connection
...
- so
...
- Maven
...
- can
...
- automatically
...
- download
...
- dependencies
A Very Brief Introduction to Java Business Integration
The Java Business Integration (JBI) spec provides a standards-based,
...
service-oriented
...
approach
...
to
...
application
...
integration
...
through
...
the
...
use
...
of
...
an
...
abstract
...
messaging
...
model,
...
without
...
reference
...
to
...
a
...
particular
...
protocol
...
or
...
wire
...
encoding.
...
JBI
...
introduces
...
the
...
concepts
...
of
...
Binding
...
Components
...
(BCs),
...
Service
...
Engines
...
(SEs)
...
to
...
Service
...
Units
...
(SUs)
...
and
...
Service
...
Assemblies
...
(SAs)
...
to
...
define
...
an
...
architecture
...
for
...
vendor-neutral
...
pluggable
...
components.
...
The
...
purpose
...
of
...
this
...
architecture
...
is
...
to
...
provide
...
standards-based
...
interoperability
...
amongst
...
components/services.
...
JBI
...
components
...
are
...
can
...
be
...
thought
...
of
...
as
...
the
...
smallest
...
applications
...
or
...
services
...
accessible
...
in
...
a
...
service-oriented
...
architecture.
...
Each
...
service
...
has
...
a
...
very
...
specific
...
purpose
...
and
...
therefore
...
a
...
narrow
...
scope
...
and
...
set
...
of
...
functionality.
...
Components
...
come
...
in
...
two
...
flavors:
...
Service
...
Engines
...
(SE)
...
and
...
Binding
...
Components
...
(BC).
...
SUs
...
must
...
be
...
packaged
...
into
...
a
...
SA
...
to
...
be
...
deployed
...
to
...
the
...
JBI
...
container.
...
An
...
SA
...
is
...
a
...
complete
...
application
...
consisting
...
of
...
one
...
or
...
more
...
services.
...
By
...
comparison,
...
this
...
is
...
similar
...
to
...
the
...
way
...
that
...
WAR
...
files
...
must
...
be
...
packaged
...
inside
...
of
...
an
...
EAR
...
file
...
to
...
be
...
deployed
...
to
...
a
...
J2EE
...
container.
...
See
...
also
...
the
...
page
...
providing
...
information
...
on
...
...
...
Below are some quick definitions the are dominant throughout the JBI spec:
- Component Architecture
- Binding Components - Components that provide or consume services via some sort of communications protocol or other remoting technology
- Service Engines - Components that supply or consume services locally (within the JBI container)
Note |
---|
The difference between binding components (BCs) and service engines (SEs) is definitely subtle and is not denoted by the JBI APIs. In fact, the only real true difference between the two is in the |
- Component Packaging
- Service Units - Packaging for an individual service that allows deployment to the JBI container; similar to a WAR file from J2EE
- Service Assemblies - Packaging for groups of SUs for deployment to the JBI container; similar to an EAR file from J2EE
This tutorial focuses on both component architecture and component packaging. For further information and details on JBI, see the following:
- The JBI spec
- The JBI section of the User's Guide
- The JBIforSOI article
- The ServiceMix as an enterprise service bus JavaWorld article
Now let's move on to creating the Maven projects for the Hello World binding component.
Creating a Maven Project For the JBI BC
The focus of this section is on the creation of a JBI binding component. For this task, a Maven archetype will be used to create a Maven project skeleton to house the component. Maven archetypes are templates for Maven projects that jumpstart project creation via the automation of repetitive tasks by following standard conventions. The result of using an archetype to create a Maven project is a directory structure, a Maven POM file and, depending on the archetype being used, sometimes Java objects and JUnit tests.
Below are the steps to follow for creating the directory structure and project. All instructions are laid out to take place on a Unix command-line.
1) Create a directory named hello-world-smx
and switch to that directory:
Code Block |
---|
units|http://incubator.apache.org/servicemix/main/working-with-service-units.html] Below are some quick definitions the are dominant throughout the JBI spec: * *Component Architecture* ** *Binding Components* - Components that provide or consume services via some sort of communications protocol or other remoting technology ** *Service Engines* - Components that supply or consume services locally (within the JBI container) {note} The difference between binding components (BCs) and service engines (SEs) is definitely subtle and is not denoted by the JBI APIs. In fact, the only real true difference between the two is in the {{jbi.xml}} descriptor in the packaging. What it really boils down to is the fact that BCs are used to do integration with a service outside the bus and SEs are services that are deployed to and solely contained within the bus. Hopefully the JBI 2.0 spec will provide more distinction. {note} * *Component Packaging* ** *Service Units* - Packaging for an individual service that allows deployment to the JBI container; similar to a WAR file from J2EE ** *Service Assemblies* - Packaging for groups of SUs for deployment to the JBI container; similar to an EAR file from J2EE This tutorial focuses on both component architecture and component packaging. For further information and details on JBI, see the following: * The [JBI spec|http://jcp.org/en/jsr/detail?id=208] * The [JBI|5. JBI] section of the [User's Guide] * The [JBIforSOI|https://open-esb.dev.java.net/public/whitepapers/JBIforSOI.pdf] article * The [ServiceMix as an enterprise service bus|http://www.javaworld.com/javaworld/jw-12-2005/jw-1212-esb.html] JavaWorld article Now let's move on to creating the Maven projects for the Hello World binding component. h2. Creating a Maven Project For the JBI BC The focus of this section is on the creation of a JBI binding component. For this task, a [Maven archetype|http://maven.apache.org/guides/introduction/introduction-to-archetypes.html] will be used to create a Maven project skeleton to house the component. Maven archetypes are templates for Maven projects that jumpstart project creation via the automation of repetitive tasks by following standard conventions. The result of using an archetype to create a Maven project is a directory structure, a [Maven POM|http://maven.apache.org/guides/introduction/introduction-to-the-pom.html] file and, depending on the archetype being used, sometimes Java objects and JUnit tests. Below are the steps to follow for creating the directory structure and project. All instructions are laid out to take place on a Unix command-line. 1) Create a directory named {{hello-world-smx}} and switch to that directory: {code} $ mkdir hello-world-smx $ cd hello-world-smx {code} |
2)
...
Use
...
the
...
servicemix-service-engine Maven archetype to generate a Maven project for the component.
To create a SE, execute the following command on the command-line:
Panel |
---|
$ mvn archetype:create \ -DarchetypeGroupId=org.apache.servicemix.tooling \
\
\
\
|
The command above will create a directory named hello-world-bc-su
...
that
...
houses
...
a
...
Maven
...
project
...
for
...
the
...
JBI
...
service
...
engine
...
being
...
created
...
here.
...
The
...
name
...
of
...
the
...
directory
...
is
...
taken
...
from
...
the
...
artifactId
...
parameter.
...
The
...
first
...
three
...
parameters
...
to
...
the
...
mvn
...
command
...
(-DarchetypeGroupId=org.apache.servicemix.tooling
...
-DarchetypeArtifactId=servicemix-binding-component
...
-DarchetypeVersion=3.1-incubating-SNAPSHOT)
...
identify
...
which
...
Maven
...
archetype
...
to
...
use
...
for
...
the
...
archetype:create
...
goal,
...
while
...
the
...
last
...
two
...
parameters
...
(-DgroupId=org.apache.servicemix.samples.helloworld.bc
...
-DartifactId=hello-world-bc-su)
...
uniquely
...
identify
...
the
...
Maven
...
project
...
that
...
is
...
being
...
generated.
...
The
...
groupId
...
is
...
used
...
as
...
the
...
Java
...
package
...
and
...
the
...
artifactId
...
is
...
used
...
as
...
the
...
project
...
name.
...
Therefore,
...
only
...
alphanumeric
...
characters
...
are
...
valid
...
values
...
for
...
the
...
groupId
...
and
...
artifactId
...
parameters.
Tip |
---|
The value of the (3.1-incubating-SNAPSHOT) may need to be updated to the current ServiceMix version in order for the command to work correctly. The latest version can always be found [ |http://fisheye3.cenqua.com/browse/servicemix/trunk/pom.xml?r=trunk]in the {{
element. {tip} The output from executing the {{ |
The output from executing the archetype:create
...
goal
...
is
...
shown
...
below:
No Format |
---|
} [INFO] Scanning for projects... [INFO] Reactor build order: [INFO] A custom project [INFO] A custom project [INFO] Hello World JBI Component [INFO] Searching repository for plugin with prefix: 'archetype'. [INFO] ---------------------------------------------------------------------------- [INFO] Building Hello World JBI Component [INFO] task-segment: [archetype:create] (aggregator-style) [INFO] ---------------------------------------------------------------------------- [INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'. [INFO] Setting property: velocimacro.messages.on => 'false'. [INFO] Setting property: resource.loader => 'classpath'. [INFO] Setting property: resource.manager.logwhenfound => 'false'. [INFO] ************************************************************** [INFO] Starting Jakarta Velocity v1.4 [INFO] RuntimeInstance initializing. [INFO] Default Properties File: org/apache/velocity/runtime/defaults/velocity.properties [INFO] Default ResourceManager initializing. (class org.apache.velocity.runtime.resource.ResourceManagerImpl) [INFO] Resource Loader Instantiated: org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader [INFO] ClasspathResourceLoader : initialization starting. [INFO] ClasspathResourceLoader : initialization complete. [INFO] ResourceCache : initialized. (class org.apache.velocity.runtime.resource.ResourceCacheImpl) [INFO] Default ResourceManager initialization complete. [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Literal [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Macro [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Parse [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Include [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Foreach [INFO] Created: 20 parsers. [INFO] Velocimacro : initialization starting. [INFO] Velocimacro : adding VMs from VM library template : VM_global_library.vm [ERROR] ResourceManager : unable to find resource 'VM_global_library.vm' in any resource loader. [INFO] Velocimacro : error using VM library template VM_global_library.vm : org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'VM_global_library.vm' [INFO] Velocimacro : VM library template macro registration complete. [INFO] Velocimacro : allowInline = true : VMs can be defined inline in templates [INFO] Velocimacro : allowInlineToOverride = false : VMs defined inline may NOT replace previous VM definitions [INFO] Velocimacro : allowInlineLocal = false : VMs defined inline will be global in scope if allowed. [INFO] Velocimacro : initialization complete. [INFO] Velocity successfully started. [INFO] [archetype:create] [INFO] Defaulting package to group ID: org.apache.servicemix.samples.helloworld.bc [INFO] ---------------------------------------------------------------------------- [INFO] Using following parameters for creating Archetype: servicemix-binding-component:3.1-incubating-SNAPSHOT [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: groupId, Value: org.apache.servicemix.samples.helloworld.bc [INFO] Parameter: packageName, Value: org.apache.servicemix.samples.helloworld.bc [INFO] Parameter: basedir, Value: /Users/bsnyder/src/hello-world-smx [INFO] Parameter: package, Value: org.apache.servicemix.samples.helloworld.bc [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: artifactId, Value: hello-world-bc-su [WARNING] org.apache.velocity.runtime.exception.ReferenceException: reference : template = archetype-resources/pom.xml [line 68,column 16] : ${servicemix-version} is not a valid reference. [WARNING] org.apache.velocity.runtime.exception.ReferenceException: reference : template = archetype-resources/pom.xml [line 73,column 16] : ${servicemix-version} is not a valid reference. [WARNING] org.apache.velocity.runtime.exception.ReferenceException: reference : template = archetype-resources/pom.xml [line 97,column 18] : ${xbean-version} is not a valid reference. [INFO] ********************* End of debug info from resources from generated POM *********************** [INFO] Archetype created in dir: /Users/bsnyder/src/hello-world-smx/hello-world-bc-su [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2 seconds [INFO] Finished at: Mon Jan 15 13:35:44 MST 2007 [INFO] Final Memory: 5M/10M [INFO] ------------------------------------------------------------------------ {noformat} |
Again,
...
Maven
...
creates
...
a
...
directory
...
using the artifactId
provided as the directory name. Inside this directory resides the pom.xml
and the src
directory. If you see the BUILD SUCCESSFUL message, proceed to the next section. Otherwise see the note below about a BUILD ERROR.
Note | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||||||
The maven-archetype-plugin 1.0-alpha4 or above is required for this tutorial. When an older version is installed, a build error will occur. The version of this plugin can be checked by verifying the name of the following directories: the {{artifactId}} provided as the directory name. Inside this directory resides the {{pom.xml}} and the {{src}} directory. If you see the BUILD SUCCESSFUL message, proceed to the next section. Otherwise see the note below about a BUILD ERROR. {note:title=In case of a BUILD ERROR: Maven plugin version requirement} The maven-archetype-plugin *1.0-alpha4* or above is required for this tutorial. When an older version is installed, a build error will occur. The version of this plugin can be checked by verifying the name of the following directories: {code:title=Unix}
In case the only version available of the maven-archetype-plugin is an older one, a minimal {{
file will need to be created manually in the {{
directory. Below is a simple POM to use for this purpose: {code:title=Minimal
|
Compiling the Project
Since we just created this project, we should first compile it just to make sure nothing is wrong with what the archetype generated. To compile, package and test the project, execute the following command from the command-line:
Code Block |
---|
{code} {note} h2. Compiling the Project Since we just created this project, we should first compile it just to make sure nothing is wrong with what the archetype generated. To compile, package and test the project, execute the following command from the command-line: {code} $ cd ./hello-world-bc-su $ mvn install {code} |
This
...
command
...
should
...
produce
...
the
...
following
...
output:
No Format |
---|
{noformat} [INFO] Scanning for projects... [INFO] artifact org.apache.servicemix.tooling:jbi-maven-plugin: checking for updates from apache.incubating [INFO] ---------------------------------------------------------------------------- [INFO] Building A custom project [INFO] task-segment: [install] [INFO] ---------------------------------------------------------------------------- [INFO] artifact org.apache.maven.plugins:maven-install-plugin: checking for updates from apache.incubating Downloading: http://people.apache.org/repo/m2-incubating-repository/xml-security/xmlsec/1.3.0/xmlsec-1.3.0.pom [WARNING] Unable to get resource from repository apache.incubating (http://people.apache.org/repo/m2-incubating-repository) Downloading: http://repo.mergere.com/maven2/xml-security/xmlsec/1.3.0/xmlsec-1.3.0.pom [WARNING] Unable to get resource from repository central (http://repo1.maven.org/maven2) Downloading: http://people.apache.org/repo/m2-incubating-repository/wss4j/wss4j/1.5.0/wss4j-1.5.0.pom [WARNING] Unable to get resource from repository apache.incubating (http://people.apache.org/repo/m2-incubating-repository) Downloading: http://repo.mergere.com/maven2/wss4j/wss4j/1.5.0/wss4j-1.5.0.pom [WARNING] Unable to get resource from repository central (http://repo1.maven.org/maven2) [INFO] [xbean:mapping {execution: default}] Checking: org.apache.servicemix.samples.helloworld.MyComponent Checking: org.apache.servicemix.samples.helloworld.MyConsumerEndpoint Checking: org.apache.servicemix.samples.helloworld.MyProviderEndpoint [INFO] Generating META-INF properties file: /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/xbean/META-INF/services/org/apache/xbean/spring/http/ org.apache.servicemix.samples.helloworld/1.0 for namespace: http://org.apache.servicemix.samples.helloworld/1.0 [INFO] Generating Spring 2.0 handler mapping: /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/xbean/META-INF/spring.handlers for namespace: http://org.apache.servicemix.samples.helloworld/1.0 [INFO] Generating Spring 2.0 schema mapping: /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/xbean/META-INF/spring.schemas for namespace: http://org.apache.servicemix.samples.helloworld/1.0 [INFO] Generating HTML documentation file: /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/xbean/hello-world-bc-su.xsd.html for namespace: http://org.apache.servicemix.samples.helloworld/1.0[INFO] Generating XSD file: /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/xbean/hello-world-bc-su.xsd for namespace: http://org.apache.servicemix.samples.helloworld/1.0 [INFO] Generating WIKI documentation file: /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/xbean/hello-world-bc-su.xsd.wiki for namespace: http://org.apache.servicemix.samples.helloworld/1.0Warning, could not load class: org.apache.servicemix.samples.helloworld.MyEndpointType: java.lang.ClassNotFoundException: org.apache.servicemix.samples.helloworld.MyEndpointType [INFO] ...done. [INFO] [jbi:generate-jbi-component-descriptor] [INFO] Generating jbi.xml [INFO] [resources:resources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:compile] Compiling 5 source files to /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/classes [INFO] [resources:testResources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:testCompile] Compiling 1 source file to /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/test-classes [INFO] [surefire:test] [INFO] Surefire report directory: /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/surefire-reports ------------------------------------------------------- T E S T S ------------------------------------------------------- Running org.apache.servicemix.samples.helloworld.MySpringComponentTest log4j:WARN No appenders could be found for logger (org.springframework.core.CollectionFactory). log4j:WARN Please initialize the log4j system properly. Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.52 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [jar:jar] [INFO] Building jar: /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/hello-world-bc-su-1.0-SNAPSHOT.jar [INFO] [jbi:jbi-component] [INFO] Generating installer /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/hello-world-bc-su-1.0-SNAPSHOT-installer.zip [INFO] Building jar: /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/hello-world-bc-su-1.0-SNAPSHOT-installer.zip [INFO] [install:install] [INFO] Installing /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/hello-world-bc-su-1.0-SNAPSHOT.jar to /Users/bsnyder/.m2/repository/org/apache/servicemix/samples/helloworld/hello-world-bc-su/1.0-SNAPSHOT/hello-world-bc-su-1.0-SNAPSHOT.jar [INFO] Installing /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/xbean/hello-world-bc-su.xsd to /Users/bsnyder/.m2/repository/org/apache/servicemix/samples/helloworld/hello-world-bc-su/1.0-SNAPSHOT/hello-world-bc-su-1.0-SNAPSHOT.xsd [INFO] Installing /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/xbean/hello-world-bc-su.xsd.html to /Users/bsnyder/.m2/repository/org/apache/servicemix/samples/helloworld/hello-world-bc-su/1.0-SNAPSHOT/hello-world-bc-su-1.0-SNAPSHOT-schema.html [INFO] Installing /Users/bsnyder/src/hello-world-smx/hello-world-bc-su/target/hello-world-bc-su-1.0-SNAPSHOT-installer.zip to /Users/bsnyder/.m2/repository/org/apache/servicemix/samples/helloworld/hello-world-bc-su/1.0-SNAPSHOT/hello-world-bc-su-1.0-SNAPSHOT-installer.zip [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 16 seconds [INFO] Finished at: Mon Jan 15 21:47:51 MST 2007 [INFO] Final Memory: 13M/31M [INFO] ------------------------------------------------------------------------ {noformat} |
Again,
...
the
...
key
...
here
...
is
...
to
...
make
...
sure
...
you
...
see
...
BUILD
...
SUCCESSFUL.
...
This
...
means
...
that
...
the
...
project
...
skeleton
...
created
...
by
...
the
...
archetype
...
was
...
compiled,
...
packaged
...
and
...
tested
...
successfully.
...
Now
...
we
...
just
...
need
...
to
...
add
...
some
...
custom
...
functionality.
...
Creating the JBI Component
Before we create any custom functionality, let's
...
first
...
examine
...
some
...
of
...
the
...
items
...
generated
...
by
...
the
...
servicemix-service-engine
...
Maven
...
archetype
...
in
...
this
...
simple
...
component
...
we're
...
developing.
...
These
...
classes
...
extend
...
class
...
from
...
either
...
the
...
...
...
APIs or from the servicemix-common
package.
pom.xml
- This is the Maven POM] file. This XML file contains all the metadata related to the project so Maven can carry out its functionality.
MyBootstrap.java
- Implementsjavax.jbi.component.Boostrap
...
- which
...
- is
...
- called
...
- by
...
- the
...
- JBI
...
- container
...
- as
...
- part
...
- of
...
- the
...
- component
...
- lifecycle
...
- (i.e.g,
...
- when
...
- the
...
- component
...
- is
...
- installed
...
- and
...
- uninstalled).
...
- This
...
- is
...
- where
...
- you
...
- place
...
- logic
...
- to
...
- set
...
- up
...
- and
...
- tear
...
- down
...
- things
...
- when
...
- the
...
- component
...
- is
...
- started
...
- and
...
- stopped.
...
MyComponent.java
...
- -
...
- Extends
...
- the
...
-
DefaultComponent
, a convenience class that makes creating JBI components much easier and provides some additional lifecycle management of components deployed to the JBI container. This class should be fleshed out by overriding methods in theDefaultComponent
to configure and initialize the component.
MyConsumerEndpoint.java
- ExtendsConsumerEndpoint
and implementsMyEndpointType
. If you'd like to create a BC that fulfills the consumer role, implement theprocess()
method in this class.
MyEndpointType.java
- This class is simply an interface marker for Apache XBean so it can generate an XML schema document.
MyProviderEndpoint.java
- ExtendsProviderEndpoint
and implementsMyEndpointType
. If you'd like to create a BC that fulfills the provider role, depending on the MEP being supported, implement theprocessInOnly()
method or theprocessInOut()
method in this class.
MySpringComponentTest.java
- A simple JUnit test class that extends a helper class to make configuring ServiceMix very easy.
src/test/resources/spring.xml
...
- -
...
- The
...
- very
...
- simple
...
- and
...
- generic
...
- ServiceMix
...
- configuration
...
- file.
...
Now
...
that
...
we've
...
gotten
...
a
...
bird's
...
eye
...
view
...
of
...
what
...
we're
...
working
...
with,
...
let's
...
proceed
...
to
...
adding
...
the
...
custom
...
functionality.
...
Adding Custom Functionality
Before creating custom functionality for the BC, you need to understand the role of a JBI BC. A BC is simply a binding to a service that is external to the JBI normalized message router (NMR) using some type of communications protocol (e.g.,
...
FTP,
...
HTTP,
...
JMS,
...
etc.).
...
It's
...
also
...
the
...
responsibility
...
of
...
the
...
BC
...
to
...
handle
...
any
...
conversion
...
of
...
the
...
message
...
format
...
into
...
...
...
that
...
can
...
be
...
sent
...
along
...
to
...
the
...
NMR.
...
This
...
is
...
known
...
as
...
message
...
normalization.
...
For
...
example,
...
if
...
we
...
were
...
to
...
create
...
a
...
BC
...
that
...
uses
...
...
as
...
the
...
application
...
layer
...
protocol,
...
the
...
SNMP
...
RFC
...
specifies
...
the
...
message
...
format
...
to
...
be
...
used
...
with
...
particular
...
versions
...
of
...
SNMP.
...
It
...
would
...
be
...
the
...
responsibility
...
of
...
the
...
BC
...
to
...
handle
...
not
...
only
...
the
...
communication
...
via
...
the
...
SNMP
...
protocol
...
but
...
also
...
to
...
handling
...
the
...
marshalling
...
of
...
SNMP
...
messages
...
to/from
...
JBI
...
normalized
...
messages.
...
The
...
BC
...
would
...
simply
...
be
...
a
...
binding
...
to
...
a
...
service
...
external
...
to
...
the
...
NMR
...
that
...
speaks
...
SNMP
...
messages
...
via
...
the
...
SNMP
...
protocol.
...
More
...
on
...
this
...
later
...
in
...
the
...
tutorial.
...
For
...
now,
...
let's
...
proceed
...
with
...
the
...
custom
...
functionality.
Note | ||
---|---|---|
| ||
It is at this stage that you should employ the use of an IDE. An IDE can dramatically reduce the work necessary to import clases, override methods and so much more. Because Maven can generate project files for Eclipse and IntelliJ IDEA, either one can be used. Throughout this tutorial, Eclipse will be used. To generate project files for Eclipse, execute the Maven |
The creation of a binding component is dependent upon the role that it will play. BCs are consumers, providers or both. Below are definitions of the two roles as they pertain to BCs:
- Consumer - A consumer BC receives requests from an external service and publishes those requests to the NMR.
- Provider - A provider BC receives requests from the NMR and publishes those requests to an external service.
This is why both the MyConsumerEndpoint.java
and the MyProviderEndpoint.java
exist when using the servicemix-binding-component archetype to create a Maven project for a SU. This way the BC that you're creating can play both the consumer role and the provider role. For the sake of this tutorial, we will create implement both roles.
First let's implement the consumer functionality. To do so, open MyConsumerEndpoint.java
and let's take a look at he process()
method as shown below:
Code Block |
---|
public void process(MessageExchange exchange) throws Exception {
// TODO: As we act as a consumer (we just send JBI exchanges)
// we will receive responses or DONE / ERROR status here
}
|
One important item of note before we get started is that this tutorial will not be accessing any services external to the JBI container. The reason for this is that setting up a service external to the JBI container would dramatically increase the complexity of this tutorial. Instead, we will just simulate such functionality by hard-coding some text to be returned.
This method is just a stub that needs to be filled in with our custom functionality. Take note of the comment in that method stub stating that this method will send JBI message exchanges and will receive responses or status messages in this method. Based on these comments, we know that we have a few tasks to handle in the implementation of this method. So let's get started.
Below is the method body that can be copied and pasted into the method stub to being adding some custom functionality. Following the display of this method, we will pick apart this method a bit to explain the various pieces of logic:
Code Block | ||
---|---|---|
| ||
{note:title=Using an IDE} It is at this stage that you should employ the use of an IDE. An IDE can dramatically reduce the work necessary to import clases, override methods and so much more. Because Maven can generate project files for Eclipse and IntelliJ IDEA, either one can be used. Throughout this tutorial, Eclipse will be used. To generate project files for Eclipse, execute the Maven {{eclipse:eclipse}} goal and then import the project into your Eclipse IDE. {note} The creation of a binding component is dependent upon the role that it will play. BCs are consumers, providers or both. Below are definitions of the two roles as they pertain to BCs: * *Consumer* - A consumer BC receives requests from an external service and publishes those requests to the NMR. * *Provider* - A provider BC receives requests from the NMR and publishes those requests to an external service. This is why both the {{MyConsumerEndpoint.java}} and the {{MyProviderEndpoint.java}} exist when using the servicemix-binding-component archetype to create a Maven project for a SU. This way the BC that you're creating can play both the consumer role and the provider role. For the sake of this tutorial, we will create implement both roles. First let's implement the consumer functionality. To do so, open {{MyConsumerEndpoint.java}} and let's take a look at he {{process()}} method as shown below: {code} public void process(MessageExchange exchange) throws Exception { // TODO: As we act as a consumer (we just send JBI exchanges) // we will receive responses or DONE / ERROR status here } {code} One important item of note before we get started is that this tutorial will not be accessing any services external to the JBI container. The reason for this is that setting up a service external to the JBI container would dramatically increase the complexity of this tutorial. Instead, we will just simulate such functionality by hard-coding some text to be returned. This method is just a stub that needs to be filled in with our custom functionality. Take note of the comment in that method stub stating that this method will send JBI message exchanges and will receive responses or status messages in this method. Based on these comments, we know that we have a few tasks to handle in the implementation of this method. So let's get started. Below is the method body that can be copied and pasted into the method stub. Following the display of this method, we will pick apart this method a bit to explain the various pieces of logic: {code:title=The {{MyConsumerEndpoint.process()}} Method} public void process(MessageExchange exchange) throws Exception { // TODO: As we act as a consumer (we just send JBI exchanges) // we will receive responses or DONE / ERROR status here // The component acts as a consumer, this means this exchange is received because // we sent it to another component. As it is active, this is either an out or a fault // If this component does not create / send exchanges, you may just throw an UnsupportedOperationException if (exchange.getRole() == MessageExchange.Role.CONSUMER) { // The component acts as a consumer, this means this exchange is received because // we sent it to another component. As it is active, this is either an out or a fault // If this component does not create / send exchanges, you may just throw an UnsupportedOperationException if (exchange.getRole() == MessageExchange.Role.CONSUMER) { // Exchange is finished if (exchange.getStatus() == ExchangeStatus.DONE) { return; // Exchange has been aborted with an exception } else if (exchange.getStatus() == ExchangeStatus.ERROR) { return; // Exchange is active } else { // Out message if (exchange.getMessage("out") != null) { // TODO ... handle the response exchange.setStatus(ExchangeStatus.DONE); getChannel().send(exchange); // Fault message } else if (exchange.getFault() != null) { // Exchange is finished TODO ... handle the fault if (exchange.getStatussetStatus() == ExchangeStatus.DONE) { ; returngetChannel().send(exchange); // ExchangeThis hasis beennot abortedcompliant with the andefault exceptionMEPs } else if (exchange.getStatus() == ExchangeStatus.ERROR) { return; { throw new IllegalStateException("Consumer exchange is ACTIVE, but no out or fault is provided"); // Exchange is active} } else { // Unknown role } else //{ Out message throw new IllegalStateException("Unkown role: " if+ (exchange.getMessagegetRole("out") != null) {); // TODO ... handle the response} } |
The method above takes into account a number of conditions, so let's go through it all. The first thing to note is that this method will only handle the consumer role. This can be seen the outermost condition as displayed below:
Code Block |
---|
if (exchange.getRole() == MessageExchange.Role.CONSUMER) { ... } else { throw new IllegalStateException("Unkown role: " + exchange.getRole()); } |
If a request comes through for the provider role, an exception will be thrown. Next, the status of the message exchange is checked to make sure it is not an error or a completed situation:
Code Block |
---|
if (exchange.getStatus() == exchange.setStatus(ExchangeStatus.DONE); { return; // Exchange has been aborted with an exception } else if getChannel()exchange.sendgetStatus(exchange); == ExchangeStatus.ERROR) { return; |
The exchange status comes directly from the JBI spec and can one of either ACTIVE, DONE or ERROR. As long a the status is ACTIVE the method proceeds on with the custom functionality. This is shown below but we have not implemented any custom logic yet:
Code Block |
---|
} else { // FaultOut message } else if (exchange.getFaultgetMessage("out") != null) { // TODO ... handle the fault response exchange.setStatus(ExchangeStatus.DONE); getChannel().send(exchange); // This is not compliant with the default MEPsFault message } else if (exchange.getFault() != } else null) { // TODO ... handle the fault throw new IllegalStateException("Consumer exchange is ACTIVE, but no out or fault is provided" exchange.setStatus(ExchangeStatus.DONE); }getChannel().send(exchange); // This is not } compliant with // Unknown rolethe default MEPs } else { throw new IllegalStateException("Unkown role: " + exchange.getRole()Consumer exchange is ACTIVE, but no out or fault is provided"); } } {code} {note:title=Important Information!} This tutorial will not be accessing any services external to the JBI container. Instead, we will just simulate such functionality by hard-coding some text to be returned. {note} imports * {{ |
Note | ||
---|---|---|
| ||
This tutorial will not be accessing any services external to the JBI container. Instead, we will just simulate such functionality by hard-coding some text to be returned. |
imports
javax.jbi.messaging.ExchangeStatus
...
This is a work in progress. I will finish this up very soon.
Testing the Hello World Binding Component
Thanks to the archetype, testing the component is very easy because it already created a test. The only change we'll make is to the string being sent by the client code. In the src/test/java
directory is the org.apache.servicemix.samples.helloworld.bc.MySpringComponentTest
...
test.
...
Simply
...
open
...
this
...
test
...
and
...
change
...
line
...
#36
...
from
...
this:
Code Block |
---|
{code} me.getInMessage().setContent(new StringSource("<hello>world</hello>")); {code} |
to
...
something
...
more
...
meaningful,
...
like
...
this:
Code Block |
---|
{code} me.getInMessage().setContent(new StringSource("<hello>Ski Colorado!</hello>")); {code} |
To
...
execute
...
the
...
test,
...
simply
...
run
...
the
...
Maven
...
install
...
goal
...
from
...
within
...
the
...
hello-world-bc-su
...
directory
...
like
...
so:
Code Block |
---|
{code} $ mvn install {code} |
Below
...
is
...
the
...
output
...
that
...
will
...
...
to
...
the
...
console:
...
No Format |
---|
Wiki Markup |
---|
Notice that not only do we see that the build was successful, but also note the text in the output above that was printed by the test (*<hello>Hello World! Message \[<hello>Ski Colorado!</hello>\] contains \[28\] bytes.</hello>*). This is the message we were expecting to be output from the test. So if you see this, you just wrote a JBI component and tested it successfully. Now this SU needs to be wrapped in a SA so it can be deployed to the JBI container. |
...
Wrapping
...
the
...
Service
...
Unit
...
in
...
a
...
Service
...
Assembly
...
The
...
component
...
we
...
created
...
above
...
and
...
packaged
...
as
...
a
...
SU
...
cannot
...
be
...
directly
...
deployed
...
to
...
a
...
JBI
...
container
...
until
...
it's
...
wrapped
...
in
...
a
...
SA.
...
This
...
can
...
be
...
done
...
by
...
creating
...
a
...
SA
...
with
...
a
...
dependency
...
on
...
the
...
SA.
...
From
...
within
...
the
...
hello-world-smx
...
directory,
...
execute
...
the
...
following
...
commands
...
to
...
create
...
the
...
project
...
for
...
the
...
SA:
Code Block |
---|
{code} $ pwd /Users/bsnyder/src/hello-world-smx/hello-world-bc-su $ cd .. $ mvn archetype:create \ -DarchetypeGroupId=org.apache.servicemix.tooling \ -DarchetypeArtifactId=servicemix-service-assembly \ -DarchetypeVersion=3.1-incubating-SNAPSHOT \ -DgroupId=org.apache.servicemix.samples.helloworld \ -DartifactId=hello-world-sa {code} |
Upon
...
successful
...
execution
...
of
...
the
...
archetype:create
...
goal,
...
look
...
for
...
the
...
BUILD
...
SUCCESSFUL
...
output
...
as
...
displayed
...
below:
No Format |
---|
{noformat} [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'archetype'. [INFO] ---------------------------------------------------------------------------- [INFO] Building Maven Default Project [INFO] task-segment: [archetype:create] (aggregator-style) [INFO] ---------------------------------------------------------------------------- [INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'. [INFO] Setting property: velocimacro.messages.on => 'false'. [INFO] Setting property: resource.loader => 'classpath'. [INFO] Setting property: resource.manager.logwhenfound => 'false'. [INFO] ************************************************************** [INFO] Starting Jakarta Velocity v1.4 [INFO] RuntimeInstance initializing. [INFO] Default Properties File: org/apache/velocity/runtime/defaults/velocity.properties [INFO] Default ResourceManager initializing. (class org.apache.velocity.runtime.resource.ResourceManagerImpl) [INFO] Resource Loader Instantiated: org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader [INFO] ClasspathResourceLoader : initialization starting. [INFO] ClasspathResourceLoader : initialization complete. [INFO] ResourceCache : initialized. (class org.apache.velocity.runtime.resource.ResourceCacheImpl) [INFO] Default ResourceManager initialization complete. [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Literal [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Macro [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Parse [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Include [INFO] Loaded System Directive: org.apache.velocity.runtime.directive.Foreach [INFO] Created: 20 parsers. [INFO] Velocimacro : initialization starting. [INFO] Velocimacro : adding VMs from VM library template : VM_global_library.vm [ERROR] ResourceManager : unable to find resource 'VM_global_library.vm' in any resource loader. [INFO] Velocimacro : error using VM library template VM_global_library.vm : org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'VM_global_library.vm' [INFO] Velocimacro : VM library template macro registration complete. [INFO] Velocimacro : allowInline = true : VMs can be defined inline in templates [INFO] Velocimacro : allowInlineToOverride = false : VMs defined inline may NOT replace previous VM definitions [INFO] Velocimacro : allowInlineLocal = false : VMs defined inline will be global in scope if allowed. [INFO] Velocimacro : initialization complete. [INFO] Velocity successfully started. [INFO] [archetype:create] [INFO] Defaulting package to group ID: org.apache.servicemix.samples.helloworld [INFO] ---------------------------------------------------------------------------- [INFO] Using following parameters for creating Archetype: servicemix-service-assembly:3.1-incubating-SNAPSHOT [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: groupId, Value: org.apache.servicemix.samples.helloworld [INFO] Parameter: packageName, Value: org.apache.servicemix.samples.helloworld [INFO] Parameter: basedir, Value: /Users/bsnyder/src/hello-world-smx [INFO] Parameter: package, Value: org.apache.servicemix.samples.helloworld [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: artifactId, Value: hello-world-sa [WARNING] org.apache.velocity.runtime.exception.ReferenceException: reference : template = archetype-resources/pom.xml [line 71,column 18] : ${servicemix-version} is not a valid reference. [INFO] ********************* End of debug info from resources from generated POM *********************** [INFO] Archetype created in dir: /Users/bsnyder/src/hello-world-smx/hello-world-sa [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2 seconds [INFO] Finished at: Fri Jan 05 23:40:32 MST 2007 [INFO] Final Memory: 4M/8M [INFO] ------------------------------------------------------------------------ {noformat} The {{ |
The hello-world-smx
...
directory
...
should
...
now
...
contain
...
the
...
following
...
two
...
directories:
Code Block |
---|
{code} $ ls hello-world-sa hello-world-bc-su {code} |
If
...
you
...
see
...
the
...
above
...
directories,
...
proceed
...
to
...
the
...
next
...
step
...
below.
...
If
...
instead
...
you
...
see
...
the
...
BUILD
...
FAILED
...
output,
...
you'll
...
need
...
to
...
analyze
...
the
...
rest
...
of
...
the
...
output
...
to
...
troubleshoot
...
the
...
issue.
...
Assistance
...
with
...
any
...
issue
...
you
...
might
...
experience
...
is
...
available
...
from
...
the
...
ServiceMix
...
community
...
via
...
the
...
...
...
...
...
.
Now that we have a project for the SA, we need to edit the POM so that the project depends upon the JBI component we created above. This can be done by editing the POM for the SA to add a dependency upon the hello-world-bc-su
...
as
...
listed
...
below:
Code Block |
---|
{code} <dependency> <groupId>org.apache.servicemix.samples.helloworld.bc</groupId> <artifactId>hello-world-bc-su</artifactId> <version>1.0-SNAPSHOT</version> </dependency> {code} |
Upon
...
adding
...
this
...
dependency
...
to
...
the
...
POM,
...
build
...
the
...
project
...
using
...
the
...
command
...
below:
Code Block |
---|
{code} $ cd hello-world-sa $ mvn install {code} {noformat} {noformat} h2. Incorporating the Projects Into a Top Level POM Now that we have created the SU and SA projects, a top level {{pom.xml}} must be manually created and made aware of each subproject. This will allow all the projects to be built automatically without having to build each project in order manually. Maven will discover all the projects and build them in the proper order. In the {{ |
No Format |
---|
Incorporating the Projects Into a Top Level POM
Now that we have created the SU and SA projects, a top level pom.xml
must be manually created and made aware of each subproject. This will allow all the projects to be built automatically without having to build each project in order manually. Maven will discover all the projects and build them in the proper order. In the hello-world-bc-su
...
directory,
...
create
...
a
...
file
...
named
...
pom.xml
...
containing
...
the
...
following
...
content:
Code Block |
---|
} <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.apache.servicemix.samples.helloworld</groupId> <artifactId>hello-world-smx</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <name>Hello World JBI Component</name> <modules> <module>hello-world-sa</module> <module>hello-world-bc-su</module> </modules> </project> {code} |
This
...
POM
...
will
...
allow
...
the
...
example
...
to
...
be
...
easily
...
folded
...
in
...
to
...
the
...
ServiceMix
...
samples.
...
The
...
<modules>
...
element
...
denotes
...
the
...
other
...
projects
...
that
...
were
...
created
...
above
...
using
...
the
...
Maven
...
archetypes.
...
Once
...
the
...
pom.xml
...
file
...
from
...
above
...
is
...
saved
...
into
...
the
...
hello-world-smx
...
directory,
...
you
...
should
...
now
...
see
...
the
...
following:
Code Block |
---|
{code} $ ls hello-world-sa hello-world-bc-su pom.xml {code} |
All
...
projects
...
can
...
now
...
be
...
built
...
using
...
the
...
following
...
command
...
on
...
the
...
command-line
...
from
...
the
...
top
...
level
...
hello-world-smx
...
directory:
Code Block |
---|
{code} $ mvn clean install {code} |
The
...
command
...
above
...
should
...
display
...
the
...
output
...
below:
...
No Format |
---|
As long as you see the BUILD SUCCESSFUL message in the output continue to the next section to give each project a unique name.
Give Each of the Maven Subprojects a Name
Notice in the output above that there are a two projects named A custom project. This is because the archetypes create projects with this generic name. Let's give each project a unique name via each component's pom.xml
file. This name will allow Maven's output to denote a component's name in its output making our development work a bit easier. To name each project, simply edit each pom.xml
and replace <name>A custom project</name>
with an appropriate name. Below are the instructions for naming each component's project:
- Edit
hello-world-sa/pom.xml
...
- and
...
- replace
...
<name>A
...
custom
...
project</name>
...
- with
...
<name>Hello
...
World
...
Service
...
Assembly</name>
...
- Edit
hello-world-bc-su/pom.xml
...
- and
...
- replace
...
<name>A
...
custom
...
project</name>
...
- with
...
<name>Hello
...
World
...
BC
...
Service
...
Unit</name>
...
Now
...
when
...
the
...
projects
...
are
...
built
...
you
...
will
...
no
...
longer
...
see
...
a
...
project
...
named
...
A
...
custom
...
project
...
.
...
Instead
...
you'll
...
now
...
see
...
Hello
...
World
...
SE
...
Service
...
Unit
...
and
...
Hello
...
World
...
Service
...
Assembly
...
.
...
Rebuild
...
the
...
projects
...
again
...
using
...
the
...
mvn
...
clean
...
install
...
command
...
on
...
the
...
command-line
...
to
...
see
...
the
...
change.
...
Deploying the Component
Now that the SA is built, we're
...
ready
...
to
...
deploy
...
it
...
to
...
the
...
JBI container.
This is a work in progress. I will finish this up very soon.
...
Note | |||
---|---|---|---|
| |||
When working with the
The configuration above introduces the {{
element to the Maven JBI plugin and sets it to false. For a few more configurable options on the Maven JBI plugin, see also [ |
Note | |||
---|---|---|---|
| |||
The default implementation of the component accepts InOut MEPs (ADD OUTLINE for further work: |https://issues.apache.org/activemq/browse/SM-605]. {note} {note:title=TODO} The default implementation of the component accepts InOut MEPs (ADD LINK TO FURTHER READING CONCERNING MEPs) and return the input content as the out message. This is already nearly what we want. OUTLINE for further work: * Get Messages * read Messages *
Classpath for SU to include manually till v3.1, see [mail|http://mail-archives.apache.org/mod_mbox/geronimo-servicemix-users/200610.mbox/%3cb23ecedc0610042315k30c03d67y240be0bb97358784@mail.gmail.com%3e] manually editing [manually till v3.1, see mail manually editing http://goopen.org/confluence/display/SM/Working+with+Service+Units ]
editing [http://www.servicemix.org/site/working-with-service-assemblies.html ]
the SU archetype like in [http://www.servicemix.org/site/creating-a-protocol-bridge.html ]
the SA archetype like in [http://www.servicemix.org/site/creating-a-protocol-bridge.html ]INS When to use this JBI Component
Using the component that you created provide exact position in the SVN \!
from SVN source like it is done at Configuration at [http://www.servicemix.org/site/visualisation.html ]maybe moving the content of overlapping existing docus to this new tut and - where appropriate - delete the old ones (only leaving a redirect). [
version14 [
version26
already fully incorporated in the mentioned versions, so delete content and point from there to here (and delete note at the very top) This shall already include everything stated at [
provide additional reading [ ].for a "bigger" example
page lists examples providing more information, showing further possibilities and components. {note} h2. Additional Resources * [Creating a Standard JBI Component] * [Notes on Creating JBI Component using maven2] * [Roadmap for a perspective Servicemix developer] |