Monday, May 14, 2012

Rest Service in Camel using CXF and Beans

This tutorial shows how to create a simple rest interface using the CXF component and beans in Camel. It is pretty straight forward but it shows all the basics. You can find the source code at: https://github.com/camelandjava/camelandjava-I

Steps:

  1. add the required dependencies in your pom
  2. create the service interface
  3. implement the interface
  4. define the bean in the camel xml context
  5. add the route for the service

1. Add dependencies:

                <!-- CXF -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jetty</artifactId>
<version>2.9.1</version>
</dependency>

2. Create the service interface

@Path("/service")
@Produces("text/xml")
public interface MyService {

@GET
@Path("/resource/{resourceId}")
public Response getResource(@PathParam("resourceId") String resourceId);
}


3. Implement the interface


public class MyServiceImpl implements MyService {

private HashMap<String, String> myResources;

private String xmlResponse = "<response code='200'><resource>REPLACE_ME</resource></response>";
private String xmlError = "<response code='400'><reason>REPLACE_ME</reason></response>";

/*
* (non-Javadoc)
*
* @see camel.workshop.service.MyService#getResource(java.lang.String)
*/

public MyServiceImpl() {
myResources = new HashMap<String, String>();
myResources.put("1", "Resouce one");
myResources.put("2", "Resouce two");
myResources.put("3", "Resouce three");
myResources.put("4", "Resouce four");
}

@Override
public Response getResource(String resourceId) {
String ret = myResources.get(resourceId);

if (ret == null) {
return Response.ok(replaceString("unknown resource", xmlError))
.build();
}

return Response.ok(replaceString(ret, xmlResponse)).build();
}

/**
* @param ret
* @return
*/
private String replaceString(String ret, String response) {
return response.replace("REPLACE_ME", ret);
}
}

4. Define the bean

ss
<?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/cxf
       http://camel.apache.org/schema/cxf/camel-cxf.xsd
       http://camel.apache.org/schema/spring
       http://camel.apache.org/schema/spring/camel-spring.xsd"
>

<!-- defining the bean -->
<ben id="resourceService" class="camel.workshop.service.impl.MyServiceImpl" />

<bean id="orderHandler" class="camel.workshop.bean.OrderHandler"/>

<camelContext xmlns="http://camel.apache.org/schema/spring">
<package>camel.workshop.routes</package>
</camelContext>

</beans>

5. Add the route for the service


public class RestService extends RouteBuilder {

/*
* (non-Javadoc)
*
* @see org.apache.camel.builder.RouteBuilder#configure()
*/
@Override
public void configure() throws Exception {

getContext().setTracing(true);

from("jetty:http://localhost:8032?matchOnUriPrefix=true")
.to("cxfbean:resourceService");
}

}


You can now run your service using the Main defined in RouteWithBeans and use a browser to check the response for an existing resource:

Or for one not in the set:


Monday, May 7, 2012

Karaf and Graylog2 (log4j appenders in general)

In order to use Graylog2 in the right way within servicemix and karaf some configuration steps are required. According to the karaf documentation these are the steps:
  1. add a new appender in <servicemix_home>/etc/org.ops4j.pax.logging.cfg
  2. generate an OSGi bundle using the Fragment-Host element in maven felix plugin 
  3. add the bundle to the servicemix installation
  4. update the DS component log4j.properties file

Step 1.

On your servicemix server go to servicemix_home directory and open the file etc/org.ops4j.pax.logging.cfg using any text editor. Add the following lines at the bottom:
#Graylogger
log4j.logger.my.package.logging.to.graylog=INFO, graylog2
log4j.appender.graylog2=org.graylog2.log.GelfAppender
log4j.appender.graylog2.graylogHost=<graylog_server_address>
log4j.appender.graylog2.facility=<application_name>
log4j.appender.graylog2.Threshold=INFO
The line in italic is actually setting the package using the graylog2 appender for the agent. Let's say we want to have DSS using graylog2 then we need to add a similar there.

Step 2.

Clone the repository from 
branch: osgi-bundle-enable
And generate the bundle using the command: mvn clean install
Note that the pom.xml already contains all the configuration for the felix plugin as defined by karaf documentation:
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>
maven
-bundle-plugin</artifactId>
                <version>2.3.5</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-Name>...</Bundle-Name>                        <Bundle-SymbolicName>...</Bundle-SymbolicName>
                        <Import-Package>!*</Import-Package>
                        <Embed-Dependency>*;scope=compile|runtime;inline=true</Embed-Dependency>
                        <Fragment-Host>org.ops4j.pax.logging.pax-logging-service</Fragment-Host>
                        <Implementation-Version>...</Implementation-Version>
                    </instructions>
                </configuration>
            </plugin>

Step 3.

Copy the generated file gelfj-0.9.1-SNAPSHOT.jar on test-integral in <servicemix_home>/system/org/ops4j/logging/gelfj/0.9.1-SNAPSHOT/gelfj-0.9.1-SNAPSHOT.jar. Generate the missing directory if needed.
The etc/startup.properties must be updated as well adding the part in bold below:
org/ops4j/pax/url/pax-url-wrap/1.2.4/pax-url-wrap-1.2.4.jar=5
org/ops4j/logging/gelfj/0.9.1-SNAPSHOT/gelfj-0.9.1-SNAPSHOT.jar=7
org/ops4j/pax/logging/pax-logging-api/1.5.3/pax-logging-api-1.5.3.jar=8
Restart servicemix: sudo /etc/init.d/servicemix restart

Step 4.

To setup the bundle that is going to log through Graylog its log4j.properties must be updated as listed below:
log4j.logger.com.nature.dsm.agent.bean.graylog=INFO, graylog2
log4j.appender.graylog2=org.graylog2.log.GelfAppender
log4j.appender.graylog2.graylogHost=<graylog_server_address>
log4j.appender.graylog2.facility=<application_name>
log4j.appender.graylog2.Threshold=INFO
Redeploy the component on your servicemix instance and have it writing some entries in Graylog2 (ie: reaching the point where your business logic is logging) then check if those entries are saved in Graylog.

Appenders in servicemix

This approach can be applied for any other appender that you want to use in any bundle either if it is using Camel in Karaf or not. As a matter of fact you generally want to have some log information written in a separate appender (ie: a file) for debugging purposes for instance.
This can be easily configured by adding the appender in etc/org.ops4j.pax.logging.cfg like:

log4j.logger.my.package.logging.to.the.file=DEBUG, F

log4j.appender.F=org.apache.log4j.DailyRollingFileAppender
log4j.appender.F.File=<servicemix_home>/data/log/app_log.log
log4j.appender.F.layout=org.apache.log4j.PatternLayout
log4j.appender.F.layout.ConversionPattern=%d{ABSOLUTE} %d{ABSOLUTE} [%5p - %t] %c: %m%n

Then add the same configuration to your bundle and redeploy. The nice thing is that you don't need to restart Karaf or Servicemix to have the new logging configuration working.

Note

Check this page out if you want to install your local instance of Graylog:

http://blog.milford.io/2012/03/installing-graylog2-0-9-6-elasticsearch-0-18-7-mongodb-2-0-3-on-centos-5-with-rvm/