ServiceMix Tutorial
SM-File, SM-JMS, SM-Bean
--------------------------------------------------------------------------------------------------------
File --> JMS Msg CH --> Bean:SimpleTransformBean.java --> JMS Msg CH --> File in other place
Installation
1. download apache-servicemix-3.3.tar.gz, extract into ESB/
2. download servicemix-example-1.zip
or you can get it from here
3. Create a directory ESB/libraries, place the JAR files ant-contrib.jar, bcel.jar, jibx-bind.jar, and jibx-run.jar, in that directory.
- JiBX is a library for Java objects --> XML, XML --> Java objects
We use JiBX to transform Java Obj. to XML to send to NMR. ( NMR only accept XML )
- Spring component framework implementations MVC, DAO, and other
important patterns. We use it for configuring POJOs (SM-Beans)
using Dependency Injection (plug sys. capabilities into biz logic component).
Basic lv. of dependency, C program making sys call. Your program depends on OS.
POSIX -- make it independent on OS.
App -> Abstract API
--> subclass for UNIX
--> subclass for Windows
App talk to Abstract API, and with some XML config., we can inject subclass to correct OS.
and Inversion of Control (your component just implement callbacks containing biz/app logic)
you call sys., sys. will call u.
Only write biz logic, no need for interaction SW.
Start ServiceMix
1. Turn off multicast feature before you start ServiceMix, otherwise our ActiveMQ broker will waste time at startup trying to make remote connections to other ServiceMix in a network.
Multicast feature allows different ServiceMix instances' ActiveMQ (JMS) brokers to discover and commicate with each other.
edit conf/activemq.xml.
Change from
to
2. run ESB/apache-servicemix-3.3/bin/servicemix
Start new Project
1. Start Eclipse with ESB/Workspace as your workspace. Create Java project osesb-example1
2. Add external JARs ( Properties -> Java build path -> Libraries ) from the directory ESB/apache-servicemix-3.3/lib
Person.java
SimpleTransformerBean.java
JiBXUtil.java in package osesb.util
copy all of the XML configuration files and the directories file/, jms/, and bean/ there.
file/xbean.xml
5. Tell Eclipse to show the ant view ( Properties > Builder > new .. ) and drag example1-build.xml from the project explorer to the ant view. You should get a list of the ant tasks defined in the file.
we can double click at "deploy" to run ant script.
It will copy to zip file and build jar file.
You can see result either on eclipse or in a serviceMix console in a command line as well.
This could fail if you have different version of jar file, or a resource location in example1-build.xml is not in a right place.
example1-build.xml
6. Bind how the fields of a Person object are related to XML elements.
The specification is compiled into Java code that implements the marshaling and unmarshaling transformations used in the bean component.
mapping.xml
7. Assembled 3 services unit into a ServiceMix service assembly by specify specification in jbi.xml configuration file. Finally, the complete archive is copied to ServiceMix's hotdeploy/ directory, where you should be able to see in the ServiceMix console the unpacking and registering of service units.
jbi.xml
8. Finally! To test our service, copy person.xml to ESB/apache-servicemix-3.3/example1/in, watch the log, and see if your transformed person is properly deposited in ESB/apache-servicemix-3.3/example1/in.
ref : mdailey
SM-File, SM-JMS, SM-Bean
--------------------------------------------------------------------------------------------------------
File --> JMS Msg CH --> Bean:SimpleTransformBean.java --> JMS Msg CH --> File in other place
Installation
1. download apache-servicemix-3.3.tar.gz, extract into ESB/
2. download servicemix-example-1.zip
or you can get it from here
3. Create a directory ESB/libraries, place the JAR files ant-contrib.jar, bcel.jar, jibx-bind.jar, and jibx-run.jar, in that directory.
- JiBX is a library for Java objects --> XML, XML --> Java objects
We use JiBX to transform Java Obj. to XML to send to NMR. ( NMR only accept XML )
- Spring component framework implementations MVC, DAO, and other
important patterns. We use it for configuring POJOs (SM-Beans)
using Dependency Injection (plug sys. capabilities into biz logic component).
Basic lv. of dependency, C program making sys call. Your program depends on OS.
POSIX -- make it independent on OS.
App -> Abstract API
--> subclass for UNIX
--> subclass for Windows
App talk to Abstract API, and with some XML config., we can inject subclass to correct OS.
and Inversion of Control (your component just implement callbacks containing biz/app logic)
you call sys., sys. will call u.
Only write biz logic, no need for interaction SW.
Start ServiceMix
1. Turn off multicast feature before you start ServiceMix, otherwise our ActiveMQ broker will waste time at startup trying to make remote connections to other ServiceMix in a network.
Multicast feature allows different ServiceMix instances' ActiveMQ (JMS) brokers to discover and commicate with each other.
edit conf/activemq.xml.
Change from
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:61616" discoveryUri="multicast://default"/>
</amq:transportConnectors>
<amq:networkConnectors>
<amq:networkConnector uri="multicast://default"/>
</amq:networkConnectors>
to
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:61616"/>
</amq:transportConnectors>
<amq:networkConnectors>
</amq:networkConnectors>
2. run ESB/apache-servicemix-3.3/bin/servicemix
Start new Project
1. Start Eclipse with ESB/Workspace as your workspace. Create Java project osesb-example1
2. Add external JARs ( Properties -> Java build path -> Libraries ) from the directory ESB/apache-servicemix-3.3/lib
- servicemix-core-3.3.jar
- servicemix-utils-1.0.0.jar
- commons-logging-1.1.jar
- org.apache.servicemix.specs.jbi-api-1.0-1.1.0.jar
- jibx-run.jar
Person.java
package osesb.example1;
public class Person {
private String customerNumber;
private String firstName;
private String lastName;
private String street;
private String city;
private String state;
private String zip;
private String phone;
// add getter and setter here.
}
SimpleTransformerBean.java
package osesb.example1;
import javax.annotation.Resource;
import javax.jbi.component.ComponentContext;
import javax.jbi.messaging.DeliveryChannel;
import javax.jbi.messaging.ExchangeStatus;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.messaging.MessagingException;
import javax.jbi.messaging.NormalizedMessage;
import javax.jbi.servicedesc.ServiceEndpoint;
import javax.xml.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.servicemix.jbi.listener.MessageExchangeListener;
import osesb.util.JiBXUtil;
// implements JBI's MessageExchangeListener interface, which allows it to receive XML messages from normalized message router.
public class SimpleTransformerBean implements MessageExchangeListener {
private static Log log = LogFactory.getLog(SimpleTransformerBean.class);
@Resource
private DeliveryChannel channel;
@Resource
private ComponentContext compContext;
public void onMessageExchange(MessageExchange exchange)
throws MessagingException {
try {
if (exchange.getStatus() != ExchangeStatus.ACTIVE)
return;
// When receiveing message, unmarshals XML message text using JiBX.
// assuming it represents a Person object
// receive "in-only" message ( because JMS Channel that connect to SM-bean:SimpleTransformBean.java is unidirectional )
Person person = (Person) JiBXUtil.unmarshalDocument(exchange.getMessage("in").getContent(), Person.class);
log.info("received person " + person.getFirstName() + " " + person.getLastName());
// makes a simple change to the object, change Firstname to John.
person.setFirstName("John");
exchange.setStatus(ExchangeStatus.DONE);
channel.send(exchange);
ServiceEndpoint targetEndpoint = compContext.getEndpoint(new QName(
"http://osesb/example1/", "JMSProviderService"),
"outQueueWriter");
MessageExchange exch = channel.createExchangeFactory(targetEndpoint)
.createInOnlyExchange();
NormalizedMessage normalizedMsg = exch.createMessage();
// Uses JiBX to marshal the modified Person object back to XML
normalizedMsg.setContent(JiBXUtil.marshalDocument(person, "UTF-8"));
// create simple String and set as "in-only" message.
exch.setMessage(normalizedMsg, "in");
// sends a message to the second JMS producer's service endpoint.
channel.send(exch);
} catch (Exception e) {
log.error("JBI bean exception", e);
throw new MessagingException("Error transforming object to or from XML");
}
}
}
JiBXUtil.java in package osesb.util
package osesb.util;4. Create a new folder resources/ at the project's top level
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IMarshallingContext;
import org.jibx.runtime.IUnmarshallingContext;
import org.jibx.runtime.JiBXException;
import org.w3c.dom.Node;
public class JiBXUtil {
public static Object unmarshalDocument(Node node, Class targetClass) throws JiBXException {
return unmarshalDocument(new DOMSource(node), targetClass);
}
public static Object unmarshalDocument(Source source, Class targetClass) throws JiBXException {
Object result = null;
try {
IUnmarshallingContext ctx = BindingDirectory.getFactory(
targetClass).createUnmarshallingContext();
result = ctx.unmarshalDocument(new StringReader(toString(source)));
} catch (Exception e) {
throw new JiBXException("Error unmarshalling XML to Object", e);
}
return result;
}
public static Source marshalDocument(Object src, String encoding)
throws JiBXException {
Source result = null;
try {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
IMarshallingContext ctx = BindingDirectory.getFactory(src.getClass())
.createMarshallingContext();
ctx.marshalDocument(src, "UTF-8", null, bOut);
result = new StreamSource(new ByteArrayInputStream(bOut.toByteArray()));
} catch (Exception e) {
throw new JiBXException("Error marshalling XML to Object",e);
}
return result;
}
private static String toString(Source source) throws TransformerException {
TransformerFactory tf = TransformerFactory.newInstance();
StringWriter sw = new StringWriter();
Transformer trans = tf.newTransformer();
trans.transform(source, new StreamResult(sw));
String result = sw.toString();
System.out.println("result " + result);
return result;
}
}
copy all of the XML configuration files and the directories file/, jms/, and bean/ there.
file/xbean.xml
<beans xmlns="http://xbean.org/schemas/spring/1.0"jms/xbean.xml
xmlns:file="http://servicemix.apache.org/file/1.0"
xmlns:esb="http://osesb/example1/">
<!-- dumps any messages it gets to the directory "example1/out"-->
<file:sender service="esb:fileSender"
endpoint="simpleFromJMSSender"
directory="example1/out">
<!-- after deploy it will create directory /media/disk/AIT/SoftwareArchitecture/ESB/apache-servicemix-3.3/example1/out -->
</file:sender>
<!-- If new file appears in directory, do something -->
<!-- specifies a file system poller that watches
the directory "example1/in/" for new files and forwards them to a JMS service endpoint.-->
<file:poller service="esb:filePoller"
endpoint="simpleToJMSPoller"
targetService="esb:JMSProviderService"
targetEndpoint="inQueueWriter"
file="example1/in"
period="2000">
<!-- after deploy it will create directory /media/disk/AIT/SoftwareArchitecture/ESB/apache-servicemix-3.3/example1/in -->
</file:poller>
</beans>
<beans xmlns:jms="http://servicemix.apache.org/jms/1.0"bean/xbean.xml
xmlns:esb="http://osesb/example1/">
<!-- 1st consumer registers for messages on "inQueue" and forwards to our ServiceMix custom Bean.-->
<jms:consumer service="esb:JMSConsumerService"
endpoint="inQueueReader"
targetService="esb:beanService"
targetEndpoint="endpoint"
destinationName="inQueue"
connectionFactory="#connectionFactory" />
<!-- 2nd consumer registers for messages on "outQueue" and forwards to the File sender's service endpoint. -->
<jms:consumer service="esb:JMSConsumerService"
endpoint="outQueueReader"
targetService="esb:fileSender"
targetEndpoint="simpleFromJMSSender"
destinationName="outQueue"
connectionFactory="#connectionFactory"/>
<!-- 1st producer receives incoming files from the File system poller and adds them to the JMS queue "inQueue" -->
<jms:provider service="esb:JMSProviderService"
endpoint="inQueueWriter"
destinationName="inQueue"
connectionFactory="#connectionFactory" />
<!-- 2nd producer receives the output from the custom Bean and adds it to the JMS queue "outQueue" -->
<jms:provider service="esb:JMSProviderService"
endpoint="outQueueWriter"
destinationName="outQueue"
connectionFactory="#connectionFactory" />
<bean id="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
</beans>
<beans xmlns:bean="http://servicemix.apache.org/bean/1.0"
xmlns:esb="http://osesb/example1/">
<classpath>
<location>.</location>
<location>jibx-run.jar</location>
</classpath>
<!--
<location>.</location>
<location>bcel.jar</location>
<location>jibx-bind.jar</location>
<location>jibx-extras.jar</location>
<location>jibx-run.jar</location>
<location>qdox-1.6.1.jar</location>
<location>stax-api.jar</location>
<location>wstx-asl.jar</location>
<location>xmlpull_1_1_4.jar</location>
<location>xpp3.jar</location>
</classpath>-->
<bean:endpoint service="esb:beanService"
endpoint="endpoint"
bean="#SimpleTransformer"/>
<bean id="SimpleTransformer"
class="osesb.example1.SimpleTransformerBean"/>
</beans>
5. Tell Eclipse to show the ant view ( Properties > Builder > new .. ) and drag example1-build.xml from the project explorer to the ant view. You should get a list of the ant tasks defined in the file.
we can double click at "deploy" to run ant script.
It will copy to zip file and build jar file.
You can see result either on eclipse or in a serviceMix console in a command line as well.
This could fail if you have different version of jar file, or a resource location in example1-build.xml is not in a right place.
example1-build.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- This ant build file is based on the example in Chapter 3 of Open Source ESBs in Action -->
<project name="ServiceMix Example 1" basedir="." default="deploy" xmlns:c="urn:contrib-ant">
<property name="classes" value="../bin" />
<property name="libraries" value="../../../libraries" />
<property name="work" location="../work" />
<property name="src" value="../src" />
<property name="src-generated" value="../src-generated" />
<property name="servicemix.home" value="../../../apache-servicemix-3.3" />
<!-- ant-contrib tasks are needed by the servicemix assembly and deployment tasks -->
<taskdef resource="net/sf/antcontrib/antlib.xml" uri="urn:contrib-ant">
<classpath>
<pathelement location="${libraries}/ant-contrib.jar" />
</classpath>
</taskdef>
<!-- JiBX binding compiler task definition -->
<taskdef name="bind" classname="org.jibx.binding.ant.CompileTask">
<classpath>
<pathelement location="${libraries}/jibx-bind.jar" />
</classpath>
</taskdef>
<!-- Test target for JiBX compilation -->
<target name="jibx-compile">
<!-- verbose="true" to show error -->
<bind verbose="true" load="true" binding="mapping.xml">
<classpath>
<pathelement path="${classes}" />
<pathelement location="${libraries}/jibx-run.jar" />
</classpath>
</bind>
</target>
<!-- Compile, create the service units, assemble them into a SA, and deploy -->
<target name="deploy">
<!-- Create the file service unit -->
<antcall target="create-serviceunit">
<param name="service-dest-file" value="example1-file-su.zip" />
<param name="servicemix-conf" value="file/" />
</antcall>
<!-- Create the JMS service unit -->
<antcall target="create-serviceunit">
<param name="service-dest-file" value="example1-jms-su.zip" />
<param name="servicemix-conf" value="jms/" />
</antcall>
<!-- Create the Spring bean service unit -->
<antcall target="create-serviceunit">
<param name="service-dest-file" value="example1-bean-su.zip" />
<param name="servicemix-conf" value="bean/" />
<param name="include-resource-dir" value="bean/resources/" />
<param name="include-classes" value="osesb/example1/**/*"/>
<param name="jibx-mapping" value="mapping.xml"/>
</antcall>
<!-- Assemble and deploy to the JBI container -->
<echo message="Create and deploy the service assembly" />
<antcall target="create-and-deploy-serviceassembly-from-serviceunits">
<param name="jbi-conf" value="." />
<param name="sm-dest-file" value="example1-sa.zip" />
<param name="service-units" value="example1-*-su.zip" />
</antcall>
</target>
<!--
Call this target with the following properties to create a serviceunit
service-dest-file: name of the service zip (must be equal to name in jbi.xml
servicemix-conf: location where the servicemix.xml or xbean file can be found
include-classes: class filter to include in the service file
resources: resources to include
-->
<target name="create-serviceunit">
<!-- some general cleanup of old files and create new directories -->
<echo message="Preparing service unit creation" />
<delete failonerror="false" file="${work}/${service-dest-file}" />
<delete failonerror="false" dir="${work}/${service-dest-file}.work" />
<mkdir dir="${work}/${service-dest-file}.work" />
<mkdir dir="${work}/${service-dest-file}.work/META-INF" />
<!--do we have a resource directory -->
<c:if>
<isset property="include-resource-dir" />
<c:then>
<echo message="Resource directory specified, including in serviceunit" />
<copy todir="${work}/${service-dest-file}.work">
<fileset dir="${include-resource-dir}">
<include name="**/*" />
</fileset>
</copy>
</c:then>
<c:else>
<echo message="No resource directory specified" />
</c:else>
</c:if>
<!--do we have a classes to copy directory -->
<c:if>
<isset property="include-classes" />
<c:then>
<echo message="Including classes into Service unit" />
<c:if>
<isset property="include-classes-archive" />
<c:then>
<echo message="compiling classes" />
<javac srcdir="${src}" destdir="${classes}">
<include name="${include-classes}" />
<include name="esb/util/framework/*" />
<classpath refid="compile.path" />
</javac>
<echo message="archiving classes to ${include-classes-archive}" />
<jar destfile="${work}/${service-dest-file}.work/${include-classes-archive}">
<fileset dir="${classes}">
<include name="${include-classes}" />
<include name="esb/util/framework/*" />
</fileset>
</jar>
</c:then>
<c:else>
<echo message="compiling classes from ${include-classes}" />
<javac srcdir="${src}" destdir="${classes}">
<include name="${include-classes}" />
<include name="esb/util/framework/*" />
<classpath refid="compile.path" />
</javac>
<copy todir="${work}/${service-dest-file}.work">
<fileset dir="${classes}">
<include name="${include-classes}" />
<include name="osesb/util/*" />
</fileset>
<fileset dir="${src}">
<include name="${include-classes}"/>
<exclude name="**/*.java"/>
</fileset>
</copy>
</c:else>
</c:if>
</c:then>
<c:else>
<echo message="No classes need to be included" />
</c:else>
</c:if>
<c:if>
<isset property="jibx-mapping" />
<c:then>
<!-- Run JiBX binding compiler -->
<bind verbose="false" load="true" binding="${jibx-mapping}">
<classpath>
<pathelement path="${classes}" />
</classpath>
</bind>
<copy todir="${work}/${service-dest-file}.work" overwrite="true">
<fileset dir="${classes}">
<include name="${include-classes}" />
</fileset>
</copy>
</c:then>
</c:if>
<c:if>
<isset property="jibx-mapping1" />
<c:then>
<bind verbose="false" load="true">
<classpath>
<pathelement path="${classes}" />
<pathelement location="${libraries}/jibx-run.jar" />
</classpath>
<bindingfileset dir="${jibx-directory}">
<include name="${jibx-mapping1}" />
<include name="${jibx-mapping2}" />
<include name="${jibx-mapping3}" />
</bindingfileset>
</bind>
<copy todir="${work}/${service-dest-file}.work" overwrite="true">
<fileset dir="${classes}">
<include name="${include-classes}" />
</fileset>
</copy>
</c:then>
</c:if>
<c:if>
<isset property="generated-classes-filter" />
<c:then>
<echo message="compiling classes from ${generated-classes-filter}" />
<javac srcdir="${src-generated}" destdir="${classes}">
<include name="${generated-classes-filter}" />
<include name="osesb/util/*" />
<classpath refid="compile.path" />
</javac>
<copy todir="${work}/${service-dest-file}.work">
<fileset dir="${classes}">
<include name="${generated-classes-filter}" />
<include name="osesb/util/*" />
</fileset>
</copy>
</c:then>
<c:else>
<echo message="No generated classes need to be included" />
</c:else>
</c:if>
<c:if>
<isset property="servicemix-conf" />
<c:then>
<echo message="Try to copy servicemix specific files, warnings can be ignored" />
<copy todir="${work}/${service-dest-file}.work" file="${servicemix-conf}/servicemix.xml" failonerror="false" />
<copy todir="${work}/${service-dest-file}.work" file="${servicemix-conf}/xbean.xml" failonerror="false" />
</c:then>
</c:if>
<c:if>
<isset property="jbi-conf" />
<c:then>
<echo message="Try to copy JBI specific files, warnings can be ignored" />
<copy todir="${work}/${service-dest-file}.work/META-INF" file="${jbi-conf}" failonerror="false" />
</c:then>
</c:if>
<jar destfile="${work}/${service-dest-file}">
<fileset dir="${work}/${service-dest-file}.work" />
</jar>
</target>
<target name="create-and-deploy-serviceassembly-from-serviceunits">
<delete failonerror="false" file="${work}/${sm-dest-file}" />
<mkdir dir="${work}/META-INF" />
<copy file="${jbi-conf}/jbi.xml" tofile="${work}/META-INF/jbi.xml" overwrite="true" />
<jar destfile="${work}/${sm-dest-file}">
<fileset dir="${work}">
<include name="META-INF/**" />
<include name="${service-units}" />
</fileset>
</jar>
<copy file="${work}/${sm-dest-file}" tofile="${servicemix.home}/hotdeploy/${sm-dest-file}" overwrite="true" />
</target>
</project>
6. Bind how the fields of a Person object are related to XML elements.
The specification is compiled into Java code that implements the marshaling and unmarshaling transformations used in the bean component.
mapping.xml
<binding>
<mapping name="person" class="osesb.example1.Person"> <!-- map person.xml in classpath into Person class -->
<value name="customer-number" field="customerNumber" />
<value name="first-name" field="firstName" />
<value name="last-name" field="lastName" />
<value name="street" field="street" />
<value name="city" field="city" />
<value name="state" field="state" />
<value name="zip" field="zip" />
<value name="phone" field="phone" />
</mapping>
</binding>
7. Assembled 3 services unit into a ServiceMix service assembly by specify specification in jbi.xml configuration file. Finally, the complete archive is copied to ServiceMix's hotdeploy/ directory, where you should be able to see in the ServiceMix console the unpacking and registering of service units.
jbi.xml
<?xml version="1.0" encoding="UTF-8"?>
<jbi xmlns="http://java.sun.com/xml/ns/jbi" version="1.0">
<service-assembly>
<identification>
<name>Example1-JMSBindingService</name>
<description>
Example showing the jms binding component
</description>
</identification>
<service-unit>
<identification>
<name>SU-BEAN</name>
<description>
The bean component
</description>
</identification>
<target>
<artifacts-zip>example1-bean-su.zip</artifacts-zip>
<component-name>servicemix-bean</component-name>
</target>
</service-unit>
<service-unit>
<identification>
<name>SU-JMS-Queue</name>
<description>
A number of ftp pollers and senders
</description>
</identification>
<target>
<artifacts-zip>example1-jms-su.zip</artifacts-zip>
<component-name>servicemix-jms</component-name>
</target>
</service-unit>
<service-unit>
<identification>
<name>SU-JMS-File</name>
<description>
A number of file pollers and senders files
</description>
</identification>
<target>
<artifacts-zip>example1-file-su.zip</artifacts-zip>
<component-name>servicemix-file</component-name>
</target>
</service-unit>
</service-assembly>
</jbi>
8. Finally! To test our service, copy person.xml to ESB/apache-servicemix-3.3/example1/in, watch the log, and see if your transformed person is properly deposited in ESB/apache-servicemix-3.3/example1/in.
<person>
<customer-number>123</customer-number>
<first-name>James</first-name>
<last-name>Doe</last-name>
<street>1st Street</street>
<city>New York</city>
<state>NY</state>
<zip>567898</zip>
<phone>1768768768</phone>
</person>
ref : mdailey
ความคิดเห็น