torsdag 1 december 2011

Gotcha when using camel-servlet

In my current project I'm using Apache Camel for the integration, and I bumped into a significant "oups"-moment while using the camel-servlet component.

I found that while I had multiple applications (WAR's) deployed I often started the wrong routes, even though I was hitting the correct endpoint url.

Say i.e. that you have two application, A and B. Both of these has the same endpoint addresses, i.e. servlet:/myservice

The logical thing would be that you could reach application A through:
http://localhost/A/myservice

and B through:
http://localhost/B/myservice

Now imagine my surprise when requests for the A application would up in the route for B. It took me a while to figure this out, but here's the reason for this...

When you expose your routes through servlet's you are using the CamelHttpTransportServlet class. An example web.xml could be something like this:

<!-- Camel servlet -->
<servlet>
<servlet-name>CamelServlet</servlet-name>
<servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<!-- Camel servlet mapping -->
<servlet-mapping>
<servlet-name>CamelServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>


Now, if you name your servlet the same for both applications you're actually only publishing one common servlet class. The camel servlet component does not take your context-root into account, which means that you hit the same endpoint irregardless whether you go to /A/myservice or /B/myservice. The one that gets hit is the one that was last deployed (or started).

Ok, easily fixed I thought... Just rename the servlet-name to something more unique for each application...
After that my routes where no longer reachable and I was just left with 404's each time I tried to hit the endpoints.
After some trial and error as well as googling I found out that if you rename your servlet from the default "CamelServlet" you *have* to specify the servlet name in your endpoint uri as well.
That is, the endpoint in application A would be i.e.:

servlet:/myService?servletName=AServlet

and B:

servlet:/myservice?servletName=BServlet

So, the lesson is:

- Always rename the camel servlet name, you never know which other applications will be deployed together on the same server. Your endpoints might clash with these and you'll have a mess figuring out why.

- Always include the servletName in your endpoint uri.

These tips should definitely be added to the documentation page to help others avoid making the same mistake.

'til next time!

torsdag 1 september 2011

Implementing your own "SOA" registry, the maven way

Saw a very interesting article on InfoQ by Ben Wilcock where he described a dead simple SOA R&R using a very pragmatic approach with Maven combined with a simple HTML app.
http://www.infoq.com/articles/SimpleServiceRepository

As an integration consultant I've worked with registries ranging from overly complex offerings (IBM Websphere Registry and Repository) to time-consuming simple wikis, but I have to say that his solution is arguably the most elegant yet.

The best part is that you both get the visibility as your schemas and contracts are available to all your stakeholders, while keeping your co-developers happy by just pointing them to a Maven project to include in their dependencies.

I'm definately hijacking this concept to my current project, and I find it very interesting that this solution has been under my nose all this time without reflecting on it.

tisdag 26 juli 2011

Camel and HornetQ as JMS provider

In my current project we're utilizing JBoss HornetQ as the messaging bus, and I wanted to try out how Camel could connect to it. My intention was to have the HornetQ instance running externally from the Camel application and connect to it. There are a bunch of examples on how to embedd HornetQ 2.2.5 (the release I'm dealing with) inside Spring, but I could'nt find a single one for how to connect to an external instance.

For my own reference I post the working solution here which uses HornetQ's JNDI to lookup the ConnectionFactory as well as a Spring JNDI template.

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<prop key="java.naming.provider.url">jnp://localhost:1099</prop>
<prop key="java.naming.factory.url.pkgs">org.jnp.interfaces:org.jboss.naming</prop>
</props>
</property>
</bean>

<bean id="jmsQueueConnectionFactory"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="jndiName">
<value>ConnectionFactory</value>
</property>
</bean>

<bean name="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
</bean>

<camel:camelContext id="context1">
<camel:route id="FirstRoute">
<camel:from uri="jms:queue:inputqueue"/>
<camel:log logName="jmsLog" message="Got message from JMS queue:"/>
<camel:to uri="jms:topic:helloworld"/>
</camel:route>
</camel:camelContext>
</beans>


And the Maven POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>camelHornet</groupId>
<artifactId>camelHornet</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<camel.version>2.8.0</camel.version>
<hornet.version>2.2.5.Final</hornet.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jms</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-core-client</artifactId>
<version>${hornet.version}</version>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms-client</artifactId>
<version>${hornet.version}</version>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms</artifactId>
<version>${hornet.version}</version>
</dependency>

<dependency>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
<version>1.1</version>
<type>jar</type>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-logging</artifactId>
<version>${hornet.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
<version>3.2.3.Final</version>
</dependency>
<dependency>
<groupId>jboss</groupId>
<artifactId>jnp-client</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.0.0.CR1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.camel</groupId>
<artifactId>camel-maven-plugin</artifactId>
<version>${camel.version}</version>
<configuration>
<applicationContextUri>META-INF/context.xml</applicationContextUri>
</configuration>
</plugin>
</plugins>
</build>
</project>

tisdag 19 april 2011

Three mindblowing days of filling my brain with new stuff

This week we at Redpill-Linpro had the great fortune to be instructed by Charles Moulliard (FuseSource) on advanced topics covering ServiceMix and Camel.

Talking from my own experience I already had quite a good grasp of Camel, but ServiceMix was probably the eye-opener for me. Until now I've previously rolled my eyes each time SM was mentioned, thinking "why do we need yet another application platform when we have web servers, Spring, JEE servers etc already?".
What I did not understand until now is the flexibility you gain when deploying your integrations to a pure OSGI stack such as Karaf (which is the layer on top of your OSGI runtime) instead of using classic hierarchical class-loading servers.

One thing that also was clear is that ServiceMix, although labeled as an ESB, is actually sort of an application server in the sense that it is not only used for integration applications. Sure, you have a lot of Camel/CXF/ActiveMQ bundles already prebuilt and ready to be utilized, but looking at the architecture it is plain to see that any type of OSGI applications could benefit by being deployed into Karaf.

I can safely say that I've bought the hype of OSGI now after finally understanding what it actually gives you. I just hope for some better tooling when it comes to declaring your package exports and imports as that seems to be an area where you'll need to perform a lot of trial and error to get correct.

We also had some good discussions concerning the fact that a lot of supplementary (Activiti, JAMES etc..) and even competing frameworks already bundle Camel to expose transport options that are not already implemented by the framework itself. JBoss ESB i.e. comes with a Camel Gateway which could be used to handle messages originating from all types of transports available in Camel that the native ESB does not have adapters for.
It will be very interesting to see how long it takes for the big players (IBM and Oracle, I'm looking at you) to bundle Camel as part of their connector strategy. I can easily fantasize about i.e. a future Camel node in the Websphere Message Broker product as a way to extend the possible transport that it could provide.

'til next time!

tisdag 5 april 2011

New career, new opportunities

Today marked my first day as an employer at the open source consultant firm Redpill-Linpro. As you readers might have noticed, my interest in OS offerings in the integration space has recently risen up to the level where I'd like to make it into a career. Therefore I chose to switch my focus and work fulltime with the projects that has so far mostly been an interesting hobby at my spare time.

Personally I think that change is a good thing and you should always try to give yourself new insights, challenges and other perspectives on your knowledge. Therefore I am leaving the trusty IBM stacks I've known to love for the last 6 years or so and head out into the unknown, starting with JBoss SOA products and the FuseSource projects (Camel, ServiceMix etc..).

With that said, I am absolutely sure that I will miss all of my colleagues at Connecta since we've had some great moments and fond memories of assignments and projects (as well as some less strict endeavours in between).

Best of luck to you all, and hope we will see each other again soon!

tisdag 22 mars 2011

Templating webservices with Velocity using Camel

When creating webservices a lot of people has objections against using JAXB for binding XML to objects. This may be because of performance reasons, allergy to generated code or simply a philosophical belief that you should not mix document centric services with an object oriented model. Whatever the reasons for not using JAXB you have I'll try to describe a possible other solution using Camel.

I created this laboration after viewing Adrian Trenamans excellent talk about CXF usage in camel, so I can and will not take credit for anything you'll see. In that talk he showed a little trick were you could use Velocity as the templating engine for generating your soap responses, without ever doing any marshalling or parsing of the XML documents.

His complete session could be found here, but do note that you need a registration at fusesource.com to see it. It is free, so if you're interested I urge you to check it out.


Defining our contract


As mostly all SOA architects would tell you should always try to start by defining a wsdl, creating the service top-down. Our intended service in this sample is going to be a very simple credit check service that accepts a customer and provides a credit score and a detailed description about the reasoning behind the score.

Our service only has one operation for now, called PerformCreditCheck:



The response is a simple message containing the Score as well as a Details field:



The Camel context


I've chosen to implement the route using the Java DSL, so after setting up the CXF endpoint in the camel context I point the package scan to the java package where my route is. The complete camel-context.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://camel.apache.org/schema/cxf"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd">

<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml"/>

<cxf:cxfEndpoint xmlns:c="http://billy.laborations/CreditCheckService/" id="creditCheckEndpoint"
address="http://localhost:9000/creditcheck"
wsdlURL="META-INF/wsdl/CreditCheckService.wsdl"
serviceName="c:CreditCheckService"
endpointName="c:CreditCheckServiceSOAP"
serviceClass="billy.laborations.creditcheck.DummyService">
<cxf:properties>
<entry key="schema-validation-enabled" value="true" />
</cxf:properties>
</cxf:cxfEndpoint>

<camelContext xmlns="http://camel.apache.org/schema/spring">
<package>billy.laborations.creditcheck</package>
</camelContext>

</beans>



As you can see I'm providing the wsdl for the service, its endpoint address as well as an implementation class.

The JAX-WS Endpoint


Looking at this class is where things are starting to get interesting. Since I don't want to deal with JAXB I chose the JAX-WS Provider type of service which accepts arbitrary messages. Any type of message that hits this service will kick of the invoke() method, leaving XML parsing etc up to the developer. If you look at the method however, you'll notice that it is set up to always throw an exception, how could it possibly work? Well, it seems that Camel hijacks this method and kicks of the route instead, but this class still needs to be existing in order for the CXF runtime to initialize.


package billy.laborations.creditcheck;

import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Provider;
import javax.xml.ws.Service.Mode;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;

@WebServiceProvider(portName="CreditCheckPort", serviceName="CreditCheckService", targetNamespace="http://billy.laborations/CreditCheckService/")
@ServiceMode(Mode.PAYLOAD)
public class DummyService implements Provider<StreamSource> {

public StreamSource invoke(StreamSource request) {
throw new UnsupportedOperationException("Not implemented yet.");
}
}



Routing


The route is implemented as:


package billy.laborations.creditcheck;

import javax.xml.transform.stream.StreamSource;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.builder.xml.Namespaces;
import org.apache.cxf.message.MessageContentsList;


public class CreditCheckRoute extends RouteBuilder {

public void configure() {
// lets define the namespaces we'll need in our filters
Namespaces ns = new Namespaces("c", "http://billy.laborations/CreditCheckService/");

from("cxf:bean:creditCheckEndpoint").routeId("CreditCheckRoute")
.process(new Processor(){
public void process(Exchange exchange) throws Exception {

//Cxf stores requests in a MessageContentList. The actual message is the first entry
MessageContentsList messageList = (MessageContentsList)exchange.getIn().getBody();
exchange.getIn().setBody(messageList.get(0), String.class);
}
})
.wireTap("seda:audit")
.setHeader("FirstName", xpath("/c:Customer/FirstName").resultType(String.class).namespaces(ns))
.setHeader("LastName", xpath("/c:Customer/LastName").resultType(String.class).namespaces(ns))
.setHeader("SocialNr", xpath("/c:Customer/SocialNr").resultType(Integer.class).namespaces(ns))
.process(new CreditCheckCalculator())
.to("velocity:META-INF/velocity/creditCheckResponse.vm")
.convertBodyTo(StreamSource.class)
;


from("seda:audit")
.inOnly()
.to("log:audit")
.to("file:target/audit/?fileName=${date:now:yyyyMMdd}.txt&fileExist=Append");
}
}



As you can see the route uses XPath to set some headers based on the incoming values. This is done so that our service (CreditCheckCalculator) has easy access to them.

The business service


I've kept the service simple in this case, but the interesting part is that it's using the camel headers for getting and setting the data. You don't have to implement the service as a camel Processor, there are a lot of ways to call i.e. an existing POJO using bean referencing, but I'll leave that for now.


package billy.laborations.creditcheck;

import org.apache.camel.Exchange;

public class CreditCheckCalculator implements org.apache.camel.Processor{

public void process(Exchange exchange) throws Exception {
String firstName = (String)exchange.getIn().getHeader("FirstName");
String lastName = (String)exchange.getIn().getHeader("LastName");
int socialNr = (Integer)exchange.getIn().getHeader("SocialNr");

int creditScore;
String details;

if(firstName.equalsIgnoreCase("Billy")){
creditScore = 99;
details = firstName + " is a really good customer!";
}else{
creditScore = 1;
details = firstName + " should not be trusted!";
}

exchange.getIn().setHeader("CreditScore", creditScore);
exchange.getIn().setHeader("Details", details);
}
}



Generating the response


Why are the headers a good place to store the result then? Well, in our case it's because we have easy access to them from the velocity template:


<CreditScore xmlns="http://billy.laborations/CreditCheckService/">
<Score>$headers.CreditScore</Score>
<Details>$headers.Details</Details>
</CreditScore>


The trick here is that we're templating our response without touching any XML API's. The velocity template will simply return a String object which we can then transform to a StreamSource before handing it back to the JAX-WS endpoint.

Final thoughts


Well, that sums up my experiment. It might look like a complex setup for a very simple service, but the benefits of using templating are:

* Performance - No need to parse the request or response messages
* WS stack - Exposing the route as an CXF endpoints gives us all the power of soap handlers and CXF injectors for i.e. adding security etc.
* Adding functionality to the route - The route can easily be extended to support other EIP patterns, such as custom auditing implemented by the wiretap in our example.

If you are interested in the code, I'll make sure to upload it. Otherwise thank you for this time!

fredag 11 mars 2011

Mule joins the GUI group

As open-source integration stacks are becoming more and more mature the final push to convince the market about their usability seems to be to provide some sort of GUI for developing your solutions.

I recently blogged about FuseSource's release of the Camel IDE, and now it seems that Mule is joining the fray by recently releasing the beta of the Mule Studio Eclipse plugin.

Read more at: http://blogs.mulesoft.org/mule-studio-beta/

So now the major OS integraiton players (Camel, Mule, JBoss ESB, Spring Integration) all have visual support for developers. I guess only time will tell how these tools will be able to keep up with the quick feature changes in the frameworks.

måndag 7 februari 2011

First Scala book in Swedish is out! Congrats guys!

On a personal note I'd like to congratulate my professional acquaintance Örjan Lundberg and his fellows Olle Kullberg and Viktor Klang for finalizing the Scala introductory book "Ett första steg i Scala". It's to my knowledge the first Swedish book to explain the concept of the Scala language.

You can find it at: http://www.studentlitteratur.se/o.o.i.s?id=2474&artnr=33847-01&csid=66&mp=4918

Congratulations guys! Hope I get the chance to read it soon!

söndag 30 januari 2011

Camel goes visual

So it seems that the Camel guys over at FuseSource has finally released the preview of the Camel development IDE. Basically an eclipse plugin that helps you author the spring xml files for your routes visually. I haven't tried it yet, but its an interesting tool which hopefully can help attract integrators into this nice framework.

There's already a short introduction up on their site, so head on to http://fusesource.com/ and have a look.

According to FuseSource they're also working on a runtime web version which you could use to inspect and author your flows directly against an executing ServiceMix/Karaf JVM.

So with Spring Integration having visual IDE support in their latest release of the STS tooling and Camel joining now it will be interesting to see what the Mule guys will bring to the table when it comes to IDE's. A sneak peak last year showed something similar (http://blogs.mulesoft.org/new-mule-ide-coming/) and you can also have a look at Saddle IDE which seems to target Mule developers as well (http://www.saddle-integration.org/).

Seems like all of them are going the XML-authoring way where your IDE generates XML configs in the background.

2011 already looks like a promising year for integration developers!