Enterprise Java

REST with Apache Camel

There are many ways to expose an HTTP endpoint in Camel: jetty, tomcat, servlet, cxfrs and restlet. Two of these components – cxfrs and restlet also support REST semantics just with few lines of code. This simple example demonstrates how to do CRUD operations with camel-restlet and camel-jdbc. The four HTTP verbs execute different operations and map to the following single URI template:

  • POST – create a new user: /user
  • GET – request the current state of the user specified by the URI: /user/{userId}
  • PUT – update an user at the given URI with new information: /user/{userId}
  • DELETE – remove the user identified by the given URI: /user/{userId}

 
 
There is also a /users URI which returns all the users regardless of the HTTP method used. Creating such an application with Camel is straightforward. After adding all the necessary dependencies (restlet, spring, jdbc…) configure web.xml to load Camel context:

<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:camel-config.xml</param-value>
    </context-param>
    <listener>
       <listener-class>org.springframework.web.context.ContextLoaderListener
 </listener-class>
    </listener>

and map the Restlet servlet

<servlet>
  <servlet-name>RestletServlet</servlet-name>
  <servlet-class>org.restlet.ext.spring.SpringServerServlet</servlet-class>
  <init-param>
    <param-name>org.restlet.component</param-name>
    <param-value>RestletComponent</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>RestletServlet</servlet-name>
  <url-pattern>/rs/*</url-pattern>
</servlet-mapping>

In the Spring context, there is a little more Restlet and an in-memory datasource setup code:

     <bean id="RestletComponent" class="org.restlet.Component"/>
    <bean id="RestletComponentService" class="org.apache.camel.component.restlet.RestletComponent">
       <constructor-arg index="0">
         <ref bean="RestletComponent"/>
       </constructor-arg>
    </bean>
    <jdbc:embedded-database id="dataSource" type="HSQL">
       <jdbc:script location="classpath:sql/init.sql"/>
    </jdbc:embedded-database> 

After all the setup is done, the next step is to create Camel routes that will process the HTTP requests and execute appropriate CRUD operations. The first one is createUser route that executes SQL insert command with the parameters from POST requests only and return the newly created user in the response body:

<route id="createUser">
   <from uri="restlet:/user?restletMethod=POST"/>
   <setBody>
     <simple>insert into user(firstName, lastName) values('${header.firstName}','${header.lastName}');  </simple>
   </setBody>
   <to uri="jdbc:dataSource"/>
   <setBody>
     <simple>select * from user ORDER BY id desc LIMIT 1</simple>
   </setBody>
   <to uri="jdbc:dataSource"/>
</route>

The ‘manipulateUser’ route handles GET, PUT and DELETE HTTP methods, but depending on the method used, it executes different SQL commands:

<route id="manipulateUser">
  <from uri="restlet:/user/{userId}?restletMethods=GET,PUT,DELETE"/>
  <choice>
    <when>
    <simple>${header.CamelHttpMethod} == 'GET'</simple>
    <setBody>
      <simple>select * from user where id = ${header.userId}</simple>
    </setBody>
   </when>
   <when>
     <simple>${header.CamelHttpMethod} == 'PUT'</simple>
       <setBody>
       <simple>update user set firstName='${header.firstName}', lastName='${header.lastName}' where id = ${header.userId}</simple>
       </setBody>
   </when>
   <when>
     <simple>${header.CamelHttpMethod} == 'DELETE'</simple>
     <setBody>
       <simple>delete from user where id = ${header.userId}</simple>
     </setBody>
   </when>
   <otherwise>
     <stop/>
   </otherwise>
  </choice>
  <to uri="jdbc:dataSource"/>
</route>

And the last route for listing all the users is self explanatory:

<route id="listUsers">
  <from uri="restlet:/users"/>
  <setBody>
    <constant>select * from user</constant>
  </setBody>
  <to uri="jdbc:dataSource"/>
</route>

If you want to see the application in action, grab the source code from github and run it with the embedded maven-jetty plugin by typing: mvn jetty:run .You can even try some quick queries if you have curl installed:

To create an user, make a http POST request with firstName and lastName parameters

curl -d 'firstName=test&lastName=user' http://localhost:8080/rs/user/

To update an existing user, make a http PUT request with firstName and lastName parameters

curl -X PUT -d 'firstName=updated&lastName=user' http://localhost:8080/rs/user/2

To retrieve an existing user, make a http GET request with the userId as part of the url

curl -X GET http://localhost:8080/rs/user/2

To delete an existing user, make a http DELETE request with the userId as part of the url

curl -X DELETE http://localhost:8080/rs/user/2

To retrieve all the existing users, make a http GET request to users url

curl -X GET http://localhost:8080/rs/users

 

Reference: REST with Apache Camel from our JCG partner Bilgin Ibryam at the OFBIZian blog.

Bilgin Ibryam

Bilgin is a software craftsman based in London, integration architect at Red Hat, Apache Camel and Apache OFBiz committer. He is an open source fanatic, passionate about distributed systems, messaging, enterprise integration patterns, and application integration. He is also the author of Camel Design Patterns and Instant Apache Camel Message Routing books.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ritwick
Ritwick
9 years ago

Hi Bilgin,
Thanks for your wonderful blog – I am actually using your example to become familiar with Camel-Restlet. I am new to Camel and am faced with an issue while deploying this code to Tomcat – I get the following exception – any idea on what needs to be done here?

Thanks,
Ritwick

javax.servlet.ServletException: Servlet.init() for servlet RestletServlet threw exception org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2441) org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2430) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) java.lang.Thread.run(Thread.java:745) root cause

java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered? org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:84) org.restlet.ext.spring.SpringServerServlet.getWebApplicationContext(SpringServerServlet.java:140) org.restlet.ext.spring.SpringServerServlet.createComponent(SpringServerServlet.java:116) org.restlet.ext.servlet.ServerServlet.getComponent(ServerServlet.java:843) org.restlet.ext.servlet.ServerServlet.init(ServerServlet.java:961) javax.servlet.GenericServlet.init(GenericServlet.java:158) org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2441) org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2430) java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) java.lang.Thread.run(Thread.java:745)

Bilgin Ibryam
9 years ago

Do you have ContextLoaderListener defined as descibed at the beginning of the tutorial?
Have you tried running cloning and running the examples above? They are available at https://github.com/bibryam/camel-example-restlet-jdbc

Ritwick
Ritwick
9 years ago

Yes Bilgin, I have added that…the issue was with the incorrect version of the dependency org.restlet.jee:org.restlet.ext.spring. I was using restlet 2.11.1 and should have gone with org.restlet.jee:org.restlet.ext.spring version 2.0.15 – instead I was using version 2.2.1. Once I changed this version to 2.0.15, it worked without any issues.
Thanks for your response Bilgin.

Sweta
Sweta
8 years ago

Hi Bling, Thanks for the wonderful explanation for the module, I am facing following error while deploying the project on Glass fish, java.lang.IncompatibleClassChangeError: class org.springframework.core.LocalVariableTableParameterNameDiscoverer$ParameterNameDiscoveringVisitor has interface org.springframework.asm.ClassVisitor as super class at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:760) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at org.glassfish.web.loader.WebappClassLoader.findClass(WebappClassLoader.java:1183) at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1728) at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1611) at org.springframework.core.LocalVariableTableParameterNameDiscoverer.inspectClass(LocalVariableTableParameterNameDiscoverer.java:112) at org.springframework.core.LocalVariableTableParameterNameDiscoverer.getParameterNames(LocalVariableTableParameterNameDiscoverer.java:85) at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:190) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1077) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:981) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:636) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:934) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) at org.apache.catalina.core.StandardContext.contextListenerStart(StandardContext.java:5362) at com.sun.enterprise.web.WebModule.contextListenerStart(WebModule.java:743) at org.apache.catalina.core.StandardContext.start(StandardContext.java:5898) at com.sun.enterprise.web.WebModule.start(WebModule.java:691) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1041) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:1024) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:747) at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:2278) at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1924) at com.sun.enterprise.web.WebApplication.start(WebApplication.java:139) at org.glassfish.internal.data.EngineRef.start(EngineRef.java:122)… Read more »

Back to top button