First steps tutorial

First steps tutorial

Prerequisites

Before you start working on this tutorial make sure that you've read the IPF development pages for setting up the development environment. For this tutorial it is not necessary to checkout the IPF sources, all IPF dependencies are downloaded from the Open eHealth Maven repository.

This tutorial is targeted at developers who want to get started with IPF and do not have a strong background on Camel and Groovy. The main goal is to have a very simple IPF application up and running very quickly. More technical background information is given in the First details tutorial.

  • We start by creating a project from an IPF archetype
  • We see how integration logic looks like in IPF, using the IPF Scripting Layer
  • We then extend integration logic in order to
    • receive a message over HTTP
    • transform that message
    • write the result to a file.
  • The messaging solution will be tested both automated and manually.
  • The messaging solution will be packaged, installed and started.

Source code

The source code for this tutorial can be downloaded from here.

Project creation

We start by creating an IPF project via a Maven archetype. Navigate to a directory of your choice and create the project by entering the following on the command line (make sure to have the command on a single line):

mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-4:generate 
-DarchetypeGroupId=org.openehealth.ipf.archetypes 
-DarchetypeArtifactId=ipf-archetype-basic 
-DarchetypeVersion=2.0.0  
-DgroupId=org.openehealth.tutorial 
-DartifactId=basic 
-Dversion=1.0-SNAPSHOT 
-DinteractiveMode=false

This will create a folder named basic in the current directory. Change to the basic folder and enter

mvn install

This will compile the project and install the project artifacts into your local Maven cache. To import the project into Eclipse navigate to File->Import->General->Existing Projects into Workspace in the Eclipse menu and select the created basic folder as root directory. After having imported the project into Eclipse it should look similar to the following figure (exact display might vary depending on your workspace settings).

Clean project after import

Eclipse might report compile errors for the imported project. In this case it is sufficient to clean the org.openehealth.tutorial.basic project. Select the project and then select Project->Clean ... from the main menu. In the dialog select Clean projects selected below (make sure that the org.openehealth.tutorial.basic project is actually selected) and press the OK button.

In addition to an IPF application skeleton the archetype also created some simple example files that can be used for initial experiments.
We'll mainly work with org.openehealth.tutorial.SampleRouteConfig.groovy in the src/main/resources path, which implements a trivial piece of message processing.

Route definition

SampleRouteBuilder.groovy defines two routes. A route is a logical unit of a sequence of message processing steps. The routes are implemented in the Groovy programming language, but we'll see that the syntax used is very close to Java.

SampleRouteBuilder.groovy
class SampleRouteBuilder extends SpringRouteBuilder {
    void configure() {
        from('direct:input1').transmogrify { it * 2 } // duplicate the request string e.g. 'abc' -> 'abcabc'
        from('direct:input2').reverse()               // revert the request string e.g. 'abc' -> 'cba'
    }
}
  1. The first route receives a message from a direct:input1 endpoint, and transmogrifies (i.e. convert to something different) the message by duplicating it. The duplication is defined by a Groovy Closure, an elegant way to define a simple code block that is executed when a message arrives. The it-variable is the Groovy default parameter to the code block, which in our case contains the message we're processing. In Groovy you can use the * (multiply) operator on a string for repeating that string.
  2. The second route that receives a message from a direct:input2 endpoint, reverses the input message body and returns the result. The reverse() command is a tutorial-specific extension defined in SampleModelExtension.groovy and is just a shortcut notation for
.transmogrify { it.reverse() }

For the moment we can treat direct endpoints as internal labels of the Camel routes, that can e.g. be used from JUnit tests like the following:

SampleRouteTest.java
...
@ContextConfiguration(locations = { "/context.xml" })
@ContextConfiguration(locations = { "/context.xml" })
public class SampleRouteTest {

    @Autowired
    private ProducerTemplate producerTemplate;
    
    @Before
    public void setUp() throws Exception {
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void testMultiply() throws Exception {
        assertEquals("abcabc", producerTemplate.requestBody("direct:input1", "abc"));
    }
    
    @Test
    public void testReverse() throws Exception {
        assertEquals("cba", producerTemplate.requestBody("direct:input2", "abc"));
    }
    
}

This test sends a message to each endpoint and expects the messages to be duplicated or reversed, respectively.

Route extension

We now extend the example to make our integration logic accessible from the outside.

  • We'll receive an HTTP request message from a jetty endpoint,
  • transform it and
  • send it to a file endpoint.

In addition we want to keep the direct endpoints so that we can still test the message transformation with the JUnit test shown above. Instead of only returning the processing result to the HTTP client we also write the message to a file. Here's the extended route definition:

SampleRouteBuilder.groovy
class SampleRouteBuilder extends SpringRouteBuilder {
    
    void configure() {

        from('jetty:http://0.0.0.0:8080/tutorial')  // receive client requests on http://0.0.0.0:8080/tutorial
            .convertBodyTo(String.class)            // convert request input stream into a string
            .to('direct:input1')                    // continue from direct:input1

        from('direct:input1')
            .transmogrify { it * 2 }                // duplicate the request string
            .setFileHeaderFrom('destination')       // set name of result file to be written (a custom DSL extension)
            .to('file:target/output')               // replace content of file in target/output directory with body of in-message.

        from('direct:input2').reverse()
    }
}
  • To receive messages over HTTP we have to create an HTTP endpoint, which will run a Jetty HTTP server listening on port 8080. The endpoint doesn't automatically convert the HTTP body from an InputStream to a String so we have to do that manually via convertBodyTo(String.class) as we expect a String body in later processing steps.
  • After converting the message, we tell the file component how to name the output file. This is done via setFileHeaderFrom(java.lang.String). In this example the file name is taken from the message header 'destination'. setFileHeaderFrom is a custom extension defined by this tutorial and must be added to the SampleModelExtension.groovy file (see next box). You don't have to understand the exact details of this extension mechanism. For now it is sufficient to see that the route definition can also contain custom elements.
  • The file endpoint finally writes the results to the target/output directory.
SampleModelExtension.groovy
class SampleModelExtension {
     static extensions = {
         ...
         ProcessorDefinition.metaClass.setFileHeaderFrom = { String sourceHeader ->  
             delegate.setHeader(Exchange.FILE_NAME) { exchange -> 
                 def destination = exchange.in.headers."$sourceHeader"
                 destination ? "${destination}.txt" : 'default.txt'
             }
         }
     }
}

Before we can start the route we additionally have to define a dependency to the camel-jetty component in our pom.xml file.

pom.xml
<project>

    <dependencies>
        ...
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-jetty</artifactId>
            <version>2.0.0</version>
        </dependency>
        ...
    </dependencies>

<project>

Project testing

Unit test

When we run the unit test SampleRouteTest.java we should see a file default.txt in the target/output folder, because we didn't set a 'destination' message header. The unit test sent the message body abc so there should be a repeated abcabc contained in the output file.

You run the test inside Eclipse or using Maven by entering

mvn test

on the command line in the basic folder.

Server test

For testing the HTTP endpoint we first have to start the server. To do so, right-click on SampleServer.java and select Run As->Java Application. This will start a standalone route or integration server that listens on port 8080 for requests. As HTTP client we use the Eclipse HTTP Client. To prepare the test open the Eclipse HTTP client and

  • Enter http://localhost:8080/tutorial in the address field (top-left corner of the window)
  • Select POST in the HTTP method field (top-right corner of the window)
  • Enter destination=custom in the Headers field
  • Enter test in the Body field

To submit the request press the green arrow at the top of the window. The result should look like:

The HTTP endpoint copies all HTTP headers onto Camel message headers, so we have the destination header present for creating a custom file name. In our example the destination header value is custom and the output file therefore has the name custom.txt. You should now see this file as well as the file generated during the unit test default.txt in the target/output folder. The content of the custom.txt file should be testtest because we sent a test HTTP request body.

Assembly and installation

We finally want to create a distribution package from our project, install (unzip) that package somewhere and start a standalone integration server (i.e. an integration server that runs outside Eclipse). Before continuing make sure that you stopped the SampleServer that you started within Eclipse, otherwise, you won't be able to start another server. To create the package enter

mvn assembly:assembly

on the command line. The created package basic-1.0-SNAPSHOT-bin.zip is written to the project's target folder. Copy the package to a new location and unzip it. This will create a folder named basic-1.0-SNAPSHOT with the following content:

Start server

To start the server run startup.bat. The console output should like like

Finally, submit the HTTP request again that you've configured before with the Eclipse HTTP client. This should again create a file custom.txt in the newly created target/output folder.

Summary

In this tutorial we've seen

  • how to create an integration project skeleton by using Maven archetypes
  • how message processing routes are defined
  • how message processing routes are tested
  • how easy it is to add HTTP or File endpoints as external interfaces
  • how an integration project is bundled and launched as a standalone application
Continue with XML processing on IPF

After this tutorial you might want to take a look at IPF's XML processing and transformation capabilities which are based on Groovy's XML support.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.