martes, abril 29, 2008

... and all he captures is endless rain.


At last entry i wrote about developing a Taget Adapter for SpringIntegration Module. In thi sentry i will talk about developing a SourceAdapter.
As my last entry, Jabber server will be used, and Smack API for connecting and receiving messages.
From previous entry server configuration, and some classes will be used, so strictly, only SourceAdapter and its configuration are going to be explain.
Firstly, but, a little explanation about two possible kind of communication for source adapters:
  • Poll: which means that every period of time the program are checking if new content is available. For example FTP Source Adapter is an example because ftp server doesn't throw an interruption when another user upload a file.
  • Driven-Event: which means that an asynchronous event is thrown and can be captured. Our IM Adapter is an example.

Each SourceAdapter must implements SourceAdapter interface. But as TargetAdapter, there are some classes that help developers in writting an Adapter. At least two classes are provided for developing a SourceAdapter that, of course, implements SourceAdapter interface:
  • AbstractSourceAdapter: A base class providing common behavior for source adapters. It has some methods for sending messages to a channel, set message mappers, ...
  • PollingSourceAdapter: A base class for polling if new message is available to be sent. It has some methods like period between polls, initial delay, ...

Our case requires extending AbstractSourceAdapter.
IMSourceAdapter extends AbstractSourceAdapter implements
InitializingBean

IMMessage is a class that represents a message sent through channel. IMMessage is a self developed class and its explanation can be found on previous post.
Because of event communication, Smack API requires that you subscribe to an event implementing an interface, so each time an event occurs, that interface is executed. This initialization is developed in initialize() Spring method and next piece of code is the business logic.


final XMPPConnection connection = new XMPPConnection(this.server); (1)
try {
connection.connect();
connection.login(this.user, this.password);
} catch (final XMPPException e) {
throw new MessageHandlingException("Error starting", e);
}

final PacketFilter packetFilter = new MessageTypeFilter(
Message.Type.chat);
connection.createPacketCollector(packetFilter); (2)

final PacketListener packetListener = new PacketListener() { (3)

@Override
public void processPacket(Packet arg0) {
String msn = ((Message) arg0).getBody(); (4)
SimpleIMMessage simpleIMMessage = new SimpleIMMessage();
simpleIMMessage.setText(msn); (5)
IMSourceAdapter.this.sendToChannel(simpleIMMessage); (6)
}
};
connection.addPacketListener(packetListener, packetFilter); (7)

(1) Uses Smack XMPPConnection for connecting to server.
(2) Creats a filter for throwing only events when a new chat message is received.
(3) Creats the business logic that must be executed each time a message is received.
(4) Gets the body of the message. (What the other user has written).
(5) Creats an IMMessage for sending through channel.
(6) Send the message through MessageChannel.
(7) Register the event.
As can be seen, the only important call is sendToChannel that sends the message to spring integration structure, the other logic may vary depending on source adapter that are going to be developed.
XML configuration file is so easy:
<?xml version="1.0" encoding="UTF-8"?>
<
beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">

<message-bus />
<annotation-driven />

<channel id="inMessage"></channel>
<beans:bean id="sourceIM" class="test.spring.integration.im.IMSourceAdapter">
<beans:property name="user" value="logger">
</beans:property>
<beans:property name="password" value="logger">
</beans:property>
<beans:property name="server" value="localhost">
</beans:property>
<beans:property name="channel" ref="inMessage">
</beans:property>
<beans:property name="messageMapper">
<beans:bean class="test.spring.integration.im.TextIMMessageMapper">
</beans:bean>
</beans:property>
</beans:bean>

<file-target directory="/temp" channel="inMessage"/>
</beans:beans>

For running the example, start the Jabber Server (OpenFire), start a client Spark, and talk to logger user. Each message will be saved one file.
SpringIntegration 1.0M3 has been used for developing the TargetAdapter.


martes, abril 15, 2008

There are four new colours on the rainbow, an old man takes polaroids ...


Spring Integration is a new project from Spring Framework developers. As it says on its website:
"Provides a programming model to support the well-known Enterprise Integration Patterns (...) and enables simple messaging within Spring-based applications and integrates with external systems via simple adapters."
In this entry, but is supposed that some basic concepts about Spring Integration are known. What we are going to explain is the development of a new adapter.
But what is an Adapter? In Spring Integration, an adapter is a component that interacts with external systems (servers, other components ...). As its name suggests, an adapter adapts the input of an external component and it transforms to something that can be sent through spring-integration pipe, and also adapts what is received from the pipe for sending to external component.
That pipe is MessageChannel class. Spring Integration is built with different adapters, JMS, RMI, Files, Mail, ... That's good while you are working with systems that required adapters are already implemented, but, what's happens if your application requires communication with an external system which an adapter has not already developed? The solution is easy, implement yourself the adapter.
That's what I am going to explain, how to implements a TargetAdapter (adapter for output messaging). In next entry would be explain how to implement a SourceAdapter (adapter for incoming messages).
Only two classes are really important org.springframework.integration.handler.MessageHandler that is used for handle the messages, and org.springframework.integration.message.AbstractMessageMapper that transform:
  1. From specific input to Spring Integration Message.
  2. From Spring Integration Message to specific output.

In this example, integration to instant messaging system will be used. The basic idea is develop a system that sent a message from Spring Integration to a XMPP server (a.k.a Jabber) user account.
Full schema of application is:

For running, apart from Spring/Spring Integration jars, JDK ..., two programs and an API are required:
  1. OpenFire, that's a XMPP server. XMPP is an open, XML-inspired protocol for near real time, extensible instant messaging (IM) and presence information. http://www.igniterealtime.org/projects/openfire/index.jsp
  2. Spark, a client for communicating with XMPP server. http://www.igniterealtime.org/projects/spark/index.jsp
  3. Smack, an API for communicating with XMPP server. http://www.igniterealtime.org/projects/smack/index.jsp

First install OpenFire server and add two users:
- login) logger password) logger
- login) incidence password) incidence
Second, install Spark, and then login with logger account and add incidence user as buddy and logout, after that login with incidence and add logger user as buddy, and don't logout.
Third, put smack jar and its dependencies into class path (Spring dependencies are there too).
Now, start the development of two most important classes:
class IMTargetAdapter implements MessageHandler, InitializingBean


Acts as an adapter through internal messages to external messages. The most important method is handle.


public Message handle(final Message msn{
final IMMessage iMessage = this.textMessage
.fromMessage((Message) msn); (1)
iMessage.setTo(this.getReceiver());
try {
this.xmppSender.send((SimpleIMMessage) iMessage); (2)
} catch (final IMException e) {
throw new MessageHandlingException("Error while sending message.",
e); (3)
}
return null;
}
(1) using a MessageMapper the spring integration message class (msn variable) is transformed to specific external system messages.
(2) using xmppSender (Facade for accessing Smack Library [out of scope of this entry]), the message is sent.
(3) case that an error occurs, MessageHandlingException must be thrown.

And finally class TextIMMessageMapper extends
AbstractMessageMapper
That has two important methods:

public IMMessage fromMessage(final Message msn) { (1)
final SimpleIMMessage simpleIMMessage = new SimpleIMMessage();
simpleIMMessage.setText(msn.getPayload());
return simpleIMMessage;
}
public Message toMessage(final IMMessage msn) { (2)
return new StringMessage(((SimpleIMMessage) msn).getText());
}
(1) transforms spring integration message to external message. SimpleIMMessage is a class that wraps messages that are sent using Smack API.
(2) transforms an external message to spring integration message (used in SourceAdapters).
Then it is time to configure the Spring XML file for configure channels and TargetAdapters so messages can be delivered to Instant Message Service.

<channel id="output"></channel> (1)

<beans:bean id="defaultMessageEndpoint" class="org.springframework.integration.endpoint.DefaultMessageEndpoint">(2)
<beans:property name="handler">
<beans:bean class="test.spring.integration.im.IMTargetAdapter">(3)
<beans:property name="xmppSender" ref="xmppIM"></beans:property>
<beans:property name="receiver" value="incidence@grumpy"></beans:property>
</beans:bean>
</beans:property>
<beans:property name="subscription">(4)
<beans:bean class="org.springframework.integration.scheduling.Subscription">
<beans:constructor-arg type="java.lang.String" value="output"></beans:constructor-arg>
</beans:bean>
</beans:property>
</beans:bean>


(1) Defines the output channel.
(2) Each component that is connected into MessageChannel must be a MessageEndpoint. DefaultMessageEndpoint is a helper class for this porpoise. Because TargetAdapter is not an Endpoint, it must be wrapped into one.
(3) Handler method is method that will be invoked by MessageEndpoint when a message is received. In this case, a MessageHandler (IMTargetAdapter) is provided, with required information (Facade for communicating with Smack API, and the receiver of messages (incidence@).
(4) MessageEndpoint must be subscribed into a channel.
Using Namehandler is out of scope of this document; of course it would be cleaner using Ext. XML authoring.
And that's all; you can download source code for trying, but remember to change receiver value.
The example has been developed using:
JDK 6.0
Eclipse 3.3

P.S. This entry was written using spring integration 1.0.0 M3