SpringOne Americas

Private Events

Blogs

View all Blogs >>
  • Ryan Shriver

    Business and Technology Consulting

    more»

  • Alex Miller

    Sr. Engineer with Terracotta Inc.

    Stanley Ho announced today on the JSR 277 mailing more»

  • Mike Levin

    Software Developer specializing in Web2.0 websites

    more»

  • Richard Monson-Haefel

    VP of Developer Relations, Curl Inc.

    more»

  • Matt Raible

    Creator of AppFuse and author of Spring Live

    more»

  • Graeme Rocher

    Project Lead of the Grails Project & CTO of G2One

    The main portal for Sky television has relaunched written in Grails. Sky, also know more»

  • Andrew Glover

    Co-author of "Continuous Integration"

    more»

  • Jason Rudolph

    Author of Getting Started with Grails

    While working on the more»

  • Jared Richardson

    Agile coach and co-author of Ship It

    Hat tip to Jeff Brown for this one. It lasts a while, but gives a great overview of Ruby, it's integration more»

  • Neal Ford

    Application Architect at ThoughtWorks, Inc.

    Way back in 1968, Edsger Dijkstra almost caused a riot at the ACM conference. His audacious crime? " more»

  • Scott Leberknight

    Chief Architect at Near Infinity

    If you are (stuck) in Javaland, which for my main project I currently am, and you'd like a little of the closure-like goodness you get from,... more»

  • Kenneth Kousen

    President of Kousen IT, Inc.

    In my previous post in this series more»

  • Stuart Halloway

    CEO of Relevance

    This article is part of a series describing a port of the samples from Practical Common Lisp more»

  • David Bock

    Principal Consultant, CodeSherpas Inc.

    I was driving to work this morning listening to all the doom and gloom on the radio, thinking to myself, "You know, I have survived a major... more»

  • Brian Pontarelli

    Brian Pontarelli - founder of Inversoft

    I might be smokin’ crack, but I think that todays (September 30th, 2008) Java update from Apple finally fixed the command-tab issue. I... more»

  • Pramod Sadalage

    Co-author of "Refactoring Databases:Evolutionary Database Development"

    Recently when our test databases where upgraded new version of Oracle, we started noticing that the order in which some drop down lists were... more»

  • Craig Walls

    Author of Spring in Action

    As you've no doubt heard and as I've already commented on elsewhere on this blog, SpringSource has enacted a new maintenance policy around... more»

  • Michael Nygard

    Agile technology leader and dynamicist

    Considering that it's 7:30 AM local time---where "local" means Aarhus, Denm more»

  • Erik Doernenburg

    Principal Consultant @ Thoughtworks

    One of my favourite tools to render graphs is Gra phViz Dot and in an more»

  • Venkat Subramaniam

    Founder of Agile Developer, Inc.

    I wrote a four part article for Java World on creating DSLs in Java and Groovy. For your convenience, I decided to list the links to those... more»

  • Jason Harwig

    Senior Software Engineer at Near Infinity

    The most popular entry I've written at Near Infinity has been the more»

  • Nathaniel Schutta

    Author, speaker, software engineer focused on user interface design.

    I spent my formative years on a small hobby farm. In addition to witnessing first hand the whole circle of life thing, I learned just how... more»

  • Ted Neward

    Enterprise, Virtual Machine and Language Wonk

    One of the more interesting logistical problems faced by the people who run the Microsoft Conference Center is that several events are often... more»

  • Brian Goetz

    Author of Java Concurrency in Practice

    I was deeply saddened at the news that David Foster Wallace committed suicide last week.  For me, the experience of reading Wallace’s more»

  • Pratik Patel

    Enterprise Architect

     Every now and then I read challenges to Frederick Brooks' wisdom. Mr. Brooks is the au more»

  • John Heintz

    Principal Consultant with New Aspects of Software

    In a recent discussion interview questions came up, here's my favorite one.To set some context this question is designed to gauge the abst more»

  • Mark Johnson

    Director of Consulting at CGI

    At the Columbus NFJS show held on July 25-27th during one of the BOF sessions Dave Bock, Scott Davis and I discussed unit tests vs functional... more»

  • Joseph Nusairat

    Author of Beginning JBoss Seam & Co-Author of Beginning Groovy & Grails

    Well i am assuming Apress has the most random site in the world at times.But today only they have our recent book, Beginning Groovy & Grai more»

  • Jeff Brown

    G2One Vice President of Professional Services - Groovy and Grails Developer

    We are really excited to have a 3 day Groovy/Grails training event coming up in Chicago later this month. The training dates are August... more»

  • Keith Donald

    Lead of Spring Web and Creator of Spring Web Flow

    I am pleased to announce that Developing Rich Web Applications with Spring, a three-day bootcamp lead by SpringSource engineers on web... more»

  • Vladimir Vivien

    Software Engineer / Consultant

    Judging from the list of features that will be included in NetBeans 6.5, more»

  • Kirk Knoernschild

    Software Developer & Mentor

    I’ve published a summary of the OSGi survey results on the APS blog more»

  • Pete Behrens

    Organizational Agility Coach

    Marti nig & Associates Methods & Tools group recentl more»

  • Brian Sam-Bodden

    Java author, Ruby geek and Open Source Advocate

    In this installment we are going to build the Dashboard page of the Tempo application. T more»

  • Mark Fisher

    Spring Integration Lead

    In my recent post, I had mentio more»

  • Ron Bodkin

    Chief Software Architect, Quantcast

    I'm looking forward to speaking at The Rich Web Experience conference in San Jose next month. The event runs from September 7th through 9th.... more»

  • Mark Goodwin

    Web Application Security Specialist

    We've already looked at one of the two big problems posed by anti DNS pinning on Java applets; because there's rebinding on the applet and... more»

  • Scott Davis

    Author of "Groovy Recipes" & TDD Expert

    Every time I see a live show at the Denver Botanic more»

  • Romain Guy

    Java User Interface expert.

    more»

  • Ramnivas Laddad

    Author of AspectJ in Action, Principal at SpringSource

    InfoQ.com has published my AOP myths and realities talk recorded at a No Fluff Just Stuff conference. InfoQ.com founded by Floyd Marine more»

  • David Geary

    Author of Graphic Java and co-author of Core JSF

    The 2006 NFJS tour kicked off t more»

  • Howard Lewis Ship

    Creator of Tapestry and HiveMind

    <p>Tapestry version 5.0.15 has been released. The good news is that this is the <strong>final beta</strong>. The bad news... more»

  • Kito Mann

    Editor-in-chief of JSF Central and the author of JSF in Action

    Our current schedule for JSF 2.0 has us handing off the spec artifacts to the JCP on 15 December 2008. That's 62 business days from today. We... more»

  • Jason Hunter

    Author of Java Servlet Programming

    I just posted the JDOM 1.1 release for download. This release includes about 20 improvements and bug fixes. more»

Spring Integration: Meet the channel adapters

Posted by: Craig Walls on 02/26/2008

A week or so ago, I wrote about how to use Spring Integration to create a new generation of File Sucker. The File Sucker from that article was not much more than a POJO that was wired in Spring to react to messages placed on a specific channel by a file source adapter.

The file source adapter is just one of many channel adapters possible with Spring Integration. As of 1.0-M1, Spring Integration comes with several ready-to-use adapters:

  • File source and target adapters
  • JMS source and target adapters
  • Byte stream source and target adapters
  • Character stream source and target adapters
  • Application event source and target adapters

The list of channel adapters from 1.0-M! is impressive--but it keeps growing as Spring Integration moves closer to 1.0. Scheduled for 1.0-M2 and 1.0-M3:

  • RMI source and target adapters (1.0-M2)
  • HttpInvoker source and target adapters (1.0-M2)
  • E-mail target adapter (1.0-M2)
  • Spring-WS source and target adapters (1.0-M3)
  • Spring MVC source adapter (1.0-M3)

Suffice it to say that by the time Spring Integration hits 1.0, there'll probably be an adapter to suit most integration needs.

Today I'm going to show off a few more of Spring Integration's adapters and also show you how to create a custom adapter, just in case your needs exceed what comes out of the box. Let's start by seeing file source adapter's mirror image: the file target adapter.

Sending messages to files

The central idea of integration is moving data from one place to another. Source adapters move information from some external source into an application, while target adapters move information out of a system to some target location (presumably to be picked up by some other application). We've already seen how a file source adapter can suck a file into an application. Now let's see how to spit messages out into files using file target adapters.

Adding a file target adapter to the Spring application context isn't much different than adding a file source adapter. Here's the file sucker application context, this time with a few new elements:

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/integration"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-2.5.xsd
        http://www.springframework.org/schema/integration
        http://www.springframework.org/schema/integration/spring-integration-1.0.xsd">

  <message-bus/>
  <channel id="fileInputChannel" />
  <channel id="fileOutputChannel" />
  <annotation-driven/>

  <context:component-scan base-package="com.habuma.si.example" />

  <file-source directory="/Users/wallsc/sucker" 
      poll-period="1000" channel="fileInputChannel"/>

  <file-target directory="/Users/wallsc/spitter" 
      channel="fileOutputChannel" />
</beans:beans>

I've added a new channel named "fileOutputChannel" for messages to travel on as they make their way to the file source target. As for the file source target itself, it is declared with the <file-target> element. The directory attribute specifies where the files will be written and the channel attribute indicates which channel that messages will be written from.

So, how do messages get into "fileOutputChannel"? Good question. For the answer, let's have another look at FileSucker:

package com.habuma.si.example;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.integration.annotation.Handler;
import org.springframework.integration.annotation.MessageEndpoint;

@MessageEndpoint(input = "fileInputChannel", 
                 defaultOutput = "fileOutputChannel")
public class FileSucker {
   private static final Logger LOGGER = 
       Logger.getLogger(FileSucker.class);

   @Handler
   public String suckAFile(String fileContents) {
      LOGGER.debug(fileContents);
      return StringUtils.reverse(fileContents);
   }
}

A few things have changed since last time. There is a new attribute on the @MessageEndpoint annotation. defaultOutput specifies the default channel that messages will be sent on. As for the messages themselves, they are returned from the suckAFile() method, which has been altered to return a String. Specifically, suckAFile() will return the contents of the file that it was given, using StringUtils (from Jakarta Commons Lang) to reverse the contents (just to make it more interesting).

With these changes, FileSucker is effectively also a file spitter. The value returned from suckAFile goes into "fileOutputChannel", from which it is picked up by the <file-target> and written to a file. File gets sucked in...file gets spit out.

One interesting thing to note at this point is that despite its name, FileSucker doesn't even realize that it's sucking and spitting files. It only knows that it is receiving a String from one channel and sending a String on another channel. How data arrives in "fileInputChannel" and how it leaves "fileOutputChannel" is none of FileSucker's concern. For that matter, if you disregard the annotations, FileSucker doesn't even know that it's being used with for integration purposes. It's simply a POJO that takes a String, reverses the String and then returns the reversed String. Put simply, FileSucker is decoupled from file reading and writing activities--and decoupling, as I think we can all agree, is a good thing.

Once you have a grasp on the basics of file adapters, working with other flavors of adapters should be straightforward. Let's see how to configure a set of JMS adapters to replace the file adapters in our example.

Using JMS adapters

Along with File Transfer, another common integration style is Messaging. In the Java world, JMS is the API of choice for transferring data in a loosely-coupled manner between applications. Spring Integration supports JMS messaging through JMS channel adapters.

Like most channel adapters supplied by Spring Integration, the JMS channel adapters comes as a matched pair of source and target adapters. These are configured in XML using the <jms-source> and <jms-target> elements. For example, here is some Spring XML configuration that configures one of each of the JMS channel adapters:

<channel id="inAndOutChannel" />


<jms-source channel="inAndOutChannel"  
    connection-factory="connectionFactory" 
    destination="inQueue"/>

<jms-target channel="inAndOutChannel" 
    connection-factory="connectionFactory" 
    destination="outTopic" />

<beans:bean id="connectionFactory" 
    class="org.apache.activemq.ActiveMQConnectionFactory">
  <beans:property name="brokerURL" value="tcp://localhost:61616" />
</beans:bean>

<beans:bean id="inQueue" 
    class="org.apache.activemq.command.ActiveMQQueue"> 
  <beans:constructor-arg index="0" value="sample.queue"/> 
</beans:bean> 

<beans:bean id="outTopic" 
    class="org.apache.activemq.command.ActiveMQTopic"> 
  <beans:constructor-arg index="0" value="sample.topic"/> 
</beans:bean> 

This is a fairly simple-minded configuration of JMS channel adapters where the <jms-source> adapter receives messages on a message queue and the <jms-target> adapter republishes them on a topic. The messages travel between each adapter via a channel named "inAndOutChannel".

There's also some additional plumbing required by both <jms-source> and <jms-target> in order to communicate with the message broker. In this example, I'm using ActiveMQ as the message broker, so I've configured an ActiveMQConnectionFactory to point to an ActiveMQ instance running on localhost, port 61616 (the default). Naturally, this assumes that ActiveMQ is running and listening on port 61616. I've also declared two destinations: one ActiveMQQueue and one ActiveMQTopic. These destinations are wired into <jms-source> and <jms-target>, respectively, for listening for and publishing messages.

This example illustrates the basic use of <jms-source> and <jms-target>, albeit in an oversimplified way. In a real-world scenario, you're more likely to have an endpoint respond to the messages published by <jms-source> or perhaps a different endpoint to push messages into the channel that is published by <jms-target>. In fact, there's nothing stating that you must have both JMS channel adapters in a single integration scenario. You may only need a <jms-source> to pull data into your application or a <jms-target> to publish messages from your application...but not necessarily both. And, for that matter, there's no reason you couldn't retrieve messages from JMS and write other messages to a file using <file-target>.

Creating custom adapters

Although Spring Integration comes packed with several useful channel adapters, your integration needs may require a custom adapter. Fortunately, Spring Integration makes it easy to register POJOs as custom adapters. For example, consider the following DateSourceAdapter

package com.habuma.si.example;
import java.util.Date;

public class DateSourceAdapter
{
    public Date whatTimeIsItNow()
    {
        return new Date();
    }
}	

There's nothing very special about DateSourceAdapter. In fact, it is a POJO in every possible sense of the acronym. However, as you'll soon see, this is a fully functional source adapter. In the Spring configuration, we'll declare DateSourceAdapter to be a source adapter:

<channel id="dateInputChannel" />
<beans:bean id="dateAdapter" 
    class="com.habuma.si.example.DateSourceAdapter" />      

<source-adapter channel="dateInputChannel" 
      period="1000" 
      ref="dateAdapter" 
      method="whatTimeIsItNow" />

Focus your attention on the <source-adapter> element, which is where the magic happens. This element declares that the bean whose ID is "dateAdapter" should have its whatTimeIsItNow() method invoked every second. Whatever value is returned fromwhatTimeIsItNow should be published into the channel named "dateInputChannel" (from which someone else will pull the value and process it).

An interesting thing to note about the whatTimeIsItNow() method is that it returns a Date object. This illustrates that messages do not have to be Strings. Messages can be composed of more complex objects, as long as the receiving endpoint or adapter knows how to deal with those types.

For example, here's DateFormatter, an endpoint that receives Date objects from "dateInputChannel", formats them, and then returns them to the message bus as Strings:

package com.habuma.si.example;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.integration.annotation.Handler;
import org.springframework.integration.annotation.MessageEndpoint;

@MessageEndpoint(input = "dateInputChannel", 
                 defaultOutput = "formattedDateChannel")
public class DateFormatter
{
    private DateFormat dateFormat;

    public DateFormatter(String format)
    {
        dateFormat = new SimpleDateFormat(format);
    }

    @Handler
    public String slurpDate(Date date)
    {
        return dateFormat.format(date);
    }
}

Again, DateFormatter is oblivious as to the source of the dates that it will format and is equally unaware of how the formatted dates will be used. It simply receives Dates as they arrive on "dateInputChannel" and drops the formatted dates off with "formattedDateChannel".

Although DateFormatter doesn't really care what will be done with the Strings that it drops into "formattedDateChannel", it might be interesting for us to see how they'll be dealt with by creating a custom target adapter to process messages on "formattedDateChannel". Here's a simple adapter that simply prints a String to stdout:

package com.habuma.si.example;

public class StdoutTargetAdapter
{
    public void printToStdout(String string)
    {
        System.out.println(string);
    }
}	

As with DateSourceAdapter, StdoutTargetAdapter is a very simple POJO. In fact, aside from its name, there's no clue that it will be used as a channel adapter. But when the following XML is placed in the Spring configuration, StdoutTargetAdapter comes to life, printing out dates that arrive in the "formattedDateChannel":

<channel id="formattedDateChannel" />
<beans:bean id="stdoutAdapter" 
    class="com.habuma.si.example.StdoutTargetAdapter" />

<target-adapter channel="formattedDateChannel" 
    ref="stdoutAdapter" 
    method="printToStdout" />

The <target-adapter> element is the key to StdoutTargetAdapter's power. It receives messages as they arrive in "formattedDateChannel" and dispatches them to the printToStdout() method of the "stdoutAdapter" bean (which happens to be StdoutTargetAdapter).

These custom adapters are rather trivial, but they should give you an idea of how to write your own adapters to solve whatever integration problems you may have.

That's all for today's exploration of Spring Integration's channel adapters. Next time, perhaps I'll dig into some of Spring Integration more by looking at tricks like routing and splitting messages. See you then!


be the first to rate this blog


About Craig Walls

Craig Walls has been professionally developing software for over 14 years (and longer than that for the pure geekiness of it). He is the author of Spring in Action (now in its second edition) and XDoclet in Action, both published by Manning and is currently writing about OSGi and Spring-DM.

When he's not slinging code, Craig spends as much time as he can with his wife, two daughters, 6 birds, and 3 dogs.