Introduction
Applications in the business world do not live in isolation, they have to cooperate and share information between themselves. In the ideal world applications can talk to each other without any problems and platform independence is commonplace. In the real world there are often silos of massive amounts of data, which are often redundant, sometimes very complex, hardly ever is it easily shared, and true platform independence is a fairy tale. It is in this world, the real world, that the hard work of integrating applications together takes place.
Enter, the Simple Integration Framework (a.k.a SimpleInt). SimpleInt is a new open source project on the CodePlex web site.
This is a simple demonstration of how to use SimpleInt to allow data to be shared from one system to another. The basic components of an integration package in the SimpleInt Framework consist of a listener, a parser, a transformer, and a sender. In this article we will walk through setting up each of these components to integrate two applications together.
Background
SimpleInt is an integration framework in the very early stages of development. Currently there is an implementation of a simple and very configurable message broker in the framework. A good place to go for an overview of the message broker pattern is http://www.patternshare.com/.
Let’s Get Started
For simplicity’s sake the example we are going to work on in this article uses the file system as the transport medium from one application to another. Our first hypothetical application places output files in one file folder and our second hypothetical application reads files from an input folder.
The integration package that we are going to create will poll the first applications output folder for new files.The integration package will read those files in and apply an XSL transform to them and place the output in our second applications input folder.
Now, we will go ahead and create an xml file that will be our input file. Let us name it input.xml
and it should read as follows:
="1.0"="utf-8"
<visit>
<doctor>1102</doctor>
<patient>107</patient>
<insurance>UHC</insurance>
<date>1/1/05</date>
</visit>
Now, create an XSL transform named changIt.xslt
that will change this xml document into another xml format.
="1.0"="UTF-8"
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8"/>
<xsl:template match="/visit">
<ecnounter>
<dateOfService>
<xsl:value-of select='date'/>
</dateOfService>
<provider>
<xsl:value-of select='doctor'/>
</provider>
<patient>
<xsl:value-of select="patient"/>
</patient>
<payor>
<xsl:value-of select="insurance"/>
</payor>
</ecnounter>
</xsl:template>
</xsl:stylesheet>
Now that we know our input and have defined our output format, create a project. Since a great company like Northwinds is always expanding and looking for new opportunities let’s go ahead and get them into the Healthcare market since our input and output data deals with going to see the doctor.
- Open Visual Studio 2005 and create a new Winforms project named
NorthwindsMedical
.
- Add a reference to the
SimpleInt.Framework.dll
.
- Include our input file,
input.xml
, and the XSL transform changeIt.xslt
in the project. Flag the changeIt.xslt
file to always be copied to the output directory.
- Add a button to
Form1
and change its text to “Start”.
- Add another button, change its text to “Stop”, and set its enabled property to
false
.
Now your form should look like this:
Now let us add some code to the form.
SimpleInt.Framework.ServiceManager _sm;
public Form1()
{
InitializeComponent();
_sm = new SimpleInt.Framework.ServiceManager();
}
We added a SimpleInt ServiceManager
field to the form class and initialized it in the form constructor. All the code we will write to manipulate the SimpleInt framework will be against this class, and there’s not a lot of code that we will write.
Now let’s start the service manager in the Start
button click event.
private void button1_Click(object sender, EventArgs e)
{
_sm.Start();
button1.Enabled = false;
button2.Enabled = true;
MessageBox.Show("Started");
}
And stop the service manager in the Stop
button click event.
private void button2_Click(object sender, EventArgs e)
{
_sm.Stop();
button1.Enabled = true;
button2.Enabled = false;
MessageBox.Show("Stopped");
}
Believe it or not, we are done coding. The rest of the article we will be setting up and configuring the service manager. We will use some of the simple implementations of parsers, listeners, translators, and senders that are already built into the SimpleInt framework. You could easily extend the framework by implementing your own parsers, senders, translators, or listeners and, in fact, that is exactly what the creators of the framework envision many developers doing. But this is a simple demonstration so we will stick to the basics.
Configuring the Service Manager
Add an App.config
file to the NorthwindsMedical
project. In that App.config
add the following configSections
:
<configSections>
<sectionGroup name="IntegrationConfig">
<section name="context"
type="Spring.Context.Support.ContextHandler, Spring.Core"/>
<section name="objects"
type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
<section name="nhibernate"
type="System.Configuration.NameValueSectionHandler, System,
Version=1.0.5000.0,Culture=neutral,
PublicKeyToken=b77a5c561934e089" />
</configSections>
This declares the IntegrationConfig
section in which we will configure the SimpleInt service manager, the nhibernate
section in which we will configure our database connection, and the log4net
section which we will not use but NHibernate and Spring.NET need.
Now we need to setup a database. (Note: In this example we will use a MSSQL Server as our data store but NHibernate allows for pretty good database independence. MySQL, Oracle, and others are supported by NHibernate out of the box and the SimpleInt framework does not care where its data is stored.) Run the CreateMessagesTable.sql
script against the MSSQL Server database you want to use for this example. With the database now set we can add the following NHibernate configuration info to the App.config
file:
<nhibernate>
<add key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider" />
<add key="hibernate.dialect"
value="NHibernate.Dialect.MsSql2000Dialect" />
<add key="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver" />
<add key="hibernate.connection.connection_string"
value="Server=(local);initial catalog=YourDB;
user id=someuser;password=somepassword" />
</nhibernate>
Now change the hibernate.connection.connection_string
value to the connection string for the database you ran the CreateMessagesTable.sql
script against.
Now add the following to the App.config
file:
<IntegrationConfig>
<context>
<resource uri="config://IntegrationConfig/objects"/>
</context>
<objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">
</objects>
</IntegrationConfig>
This is the section where most of the magic is going to happen. We will come back to this soon.
Add the following to the App.config
to keep log4net
happy:
<log4net>
<logger name="testApp.Logging">
<level value="DEBUG"/>
</logger>
</log4net>
Now back to the meat of the configuration. Inside the objects
tags in the IntegrationConfig
section we are going to wire up an instance of the SimpleInt.Framework.Processor
class. Add the following xml inside the objects
tags:
<object name="IntegrationProcessor"
type="SimpleInt.Framework.Processor, SimpleInt.Framework"
singleton="true">
<property name="DataStore">
<ref object="IntegrationDataStore"/>
</property>
<property name="IntegrationPackages">
<list>
<ref object="TestPackage"/>
</list>
</property>
</object>
It is very important that the name
of this object
be correct (IntegrationProcessor
) because it is the name that the SimpleInt service manager will be looking for. Notice that we have configured this class as a singleton, so only one instance of this object will be created for the life of the service manager. Also, we have set the DataStore
and IntegrationPackages
properties. The DataStore
property references an object named IntegrationDataStore
, which we will configure later. The IntegrationPackages
property is a collection, so any object that needs to be added to that collection goes in between the list
tags.
Now let’s set up the TestPackage
integration package and all of its supporting objects. Add the following xml inside the objects
tags:
<object name="TestPackage"
type="SimpleInt.Framework.IntegrationPackage, SimpleInt.Framework"
singleton="true">
<property name="Name">
<value>Test</value>
</property>
<property name="Listener">
<ref object="TestListener"/>
</property>
<property name="Parser">
<ref object="TestParser"/>
</property>
<property name="Translator">
<ref object="TestTranslator"/>
</property>
<property name="Sender">
<ref object="TestSender"/>
</property>
</object>
<object name="TestListener"
type="SimpleInt.SimpleImplementations.Listeners.
FilePollingListener, SimpleInt.Framework"
singleton="true">
<property name="FolderPath">
<value>Input</value>
</property>
<property name="ArchiveFolder">
<value>Archive</value>
</property>
</object>
<object name="TestParser"
type="SimpleInt.SimpleImplementations.Parsers.
PassThroughParser, SimpleInt.Framework"
singleton="true">
</object>
<object name="TestTranslator"
type="SimpleInt.SimpleImplementations.Translators.
XsltTranslator, SimpleInt.Framework"
singleton="true">
<property name="XsltFile">
<value>changeIt.xslt</value>
</property>
</object>
<object name="TestSender"
type="SimpleInt.SimpleImplementations.Senders.FileSender,
SimpleInt.Framework"
singleton="true">
<property name="Folder">
<value>Output</value>
</property>
<property name="FileType">
<value>.out</value>
</property>
</object>
Notice we are using a PassThroughParser
(TestParser
) and we are using the XsltTranslator
, which we have configured to use the changeIt.xslt
file we created earlier. We are also using a FilePollingListener
and a FileSender
.
So based on the configuration above, the listener will grab any file placed in the Input
folder, read it into the system as a new message, and move it to the Archive
folder. The parser will just pass the message on to the translator as is. The translator will apply the changeIt.xslt
transform to the message and the sender will write the translated message to the Output
folder as a new file with a “.out” file extension.
Now we need to add the folders mentioned above in the right place. In your project output folder (ususally bin\Debug
) create three folders: Input
, Archive
, and Output
.
Sweet… Not too bad for 3 lines of SimpleInt specific code and some xml.
Now let’s finish up and configure the data store. Add the following xml inside the objects
tags:
<object name="cfg"
type="SimpleInt.SimpleImplementations.MessageDataStores.
Hibernate.NHibernateConfiguration, SimpleInt.Framework"
singleton="true">
<property name="Assemblies">
<list>
<value>SimpleInt.Framework</value>
</list>
</property>
</object>
<object name="sessionFactory"
factory-method="CreateSessionFactory" factory-object="cfg"/>
<object name="IntegrationDataStore"
type="SimpleInt.SimpleImplementations.MessageDataStores.
SimpleDBDataStore, SimpleInt.Framework"
singleton="true">
<property name="NHibernateSessionFactory">
<ref object="sessionFactory"/>
</property>
</object>
Here we are just configuring and initializing the SimpleDBDataStore
, which uses NHibernate to handle database calls to store and log the messages that are processed.
Now we are ready to run it.
Running the Demo
Now hit F5 to build the project and run it. When Form1
pops up, push start. After you click the “started” message box, put a copy of the input.xml
file into the Input
folder. That file should disappear from that folder in a second or so. After it has disappeared, verify that a copy of the input.xml
file is now in the Archive
folder and that a new file is in the Output
folder. The contents of that file should be the contents of the input file translated into the format that our second application needs, and it should look like this:
="1.0"="utf-16"
<ecnounter>
<dateOfService>1/1/05</dateOfService>
<provider>1102</provider>
<patient>107</patient>
<payor>UHC</payor>
</ecnounter>
Again, not too bad for 3 lines of SimpleInt specific code and some xml, is it?
Points of Interest
The ability to wire objects together in a config file and then have an application run based on that wiring is pretty cool. Spring.Net has some great dependency injection and inversion of control abilities. Also SimpleInt has plans to add a message bus set of features as the framework grows.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.