Sparkles

that were shone when I got tempered!

Posts Tagged ‘REST API

Demo REST project with Camel CXF

leave a comment »

1. Create a .war project (java 1.7 or above) using Maven as follows.

Here we are using the eclipse as the IDE and the Maven. The prefered java version is 1.7 or greater.

1-create_maven_war_prj

2. This is the folder structure of it once it is created.

2-folderStructure

3. Include the necessary dependencies to the pom.xml file as follows.

Here, we’re mainly include the Apache Camel (including camel cxf jars), Apache Common IO and SLF4j jars. Camel is using Common IO internally so it must be also used. And spring jars are also used in here. Springs are used to load the ApplicationContexts automatically.


<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>demo.restapi</groupId>
<artifactId>demo.restapi</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<name>Rest API demo project</name>
<description>Rest API demo project</description>

<properties>
<camel-web>2.5.0</camel-web>
<camel-version>2.12.0</camel-version>
<xbean-spring-version>3.5</xbean-spring-version>
</properties>

<dependencies>

<!-- Spring + Camel jars -->

<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>${xbean-spring-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.apache.camel</groupId>
<artifactId>camel-stream</artifactId>
<version>${camel-version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>

<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<version>${camel-version}</version>
</dependency>

<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf-transport</artifactId>
<version>${camel-version}</version>
</dependency>

<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>2.7.6</version>
</dependency>

<!-- Other jars (logging, io etc) -->

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>

</dependencies>

</project>

4. Add the below configurations to the WEB-INF/web.xml

Here, we are adding the applicationContext.xml as the contextConfigLocation and the listener classes. Package of the  all routers implementation classes must be mentioned in the applicationContext.xml.


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:web="http://xmlns.jcp.org/xml/ns/javaee"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <context-param>
 <param-name>test</param-name>
 <param-value>true</param-value>
 </context-param>
 <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>/WEB-INF/applicationContext.xml</param-value>
 </context-param>
 <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
</web-app>

5. Add the below configurations to the WEB-INF/applicationContext.xml.

The package containing all the routes must be specified in the camelContext/camel:package tag. Here in our demo project, the router is mentioned in the camel.route package.


<?xml version="1.0" encoding="UTF-8"?>
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
 license agreements. See the NOTICE file distributed with this work for additional
 information regarding copyright ownership. The ASF licenses this file to
 You under the Apache License, Version 2.0 (the "License"); you may not use
 this file except in compliance with the License. You may obtain a copy of
 the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
 by applicable law or agreed to in writing, software distributed under the
 License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 OF ANY KIND, either express or implied. See the License for the specific
 language governing permissions and limitations under the License. -->

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

<bean id="contextApplicationContextProvider" class="conf.ApplicationCtxProvider"></bean>

 <camelContext xmlns="http://camel.apache.org/schema/spring"
 id="Demo-Camel">

 <!-- All the Routes should be created within below Package -->
 <camel:package>camel.route</camel:package>

 </camelContext>

</beans>

6. Add the ApplicationContext classes

These classes are loaded during the Spring-Initialization.

a. ApplicationCtxProvider

This class which implements ApplicationContextAware, is automatically loaded during Spring-Initialization.


package conf;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class ApplicationCtxProvider implements ApplicationContextAware {

@Override
public void setApplicationContext(ApplicationContext ctx)
throws BeansException {
ApplicationCtx.setApplicationContext(ctx);
}
}

b.ApplicationCtx.

This is injected from the class “ApplicationCtxProvider” which is automatically loaded during Spring-Initialization. This get access to the Spring ApplicationContext from everywhere in your Application.


package conf;

import org.springframework.context.ApplicationContext;

public class ApplicationCtx {

private static ApplicationContext ctx;

// Injected from the class "ApplicationCtxProvider" which is automatically loaded during Spring-Initialization.

public static void setApplicationContext(
ApplicationContext applicationContext) {
ctx = applicationContext;
}

// Get access to the Spring ApplicationContext from everywhere in your Application.

public static ApplicationContext getApplicationContext() {
return ctx;
}
}

7. Implement the Camel router (DemoRouteBuilder).

This class is the router that takes all the REST calls to our REST service. To be run automatically, this must be included in the camel.route as it is mentioned in the aplicationContext.xml. So, it will run automatically start to run when the server is starting. Here we are mentioning the cxfrs URI that will be considered as the Endpoint URI. Here we should specify the resourceClasses to point the request to the implementation. Here,  http://localhost:9003/rest is considered as the root URI for the REST service. Rest of the path will be defined in the resource classes. Here, MappingProcessor implements the Camel Process


package camel.route;

import org.apache.camel.builder.RouteBuilder;

import camel.process.MappingProcessor;
import rs.DemoRequestServiceImpl;

public class DemoRouteBuilder extends RouteBuilder {

private static final String REST_ENDPOINT_URI = "cxfrs://http://localhost:9003/rest?resourceClasses=rs.DemoRequestServiceImpl";

@Override
public void configure() {
errorHandler(noErrorHandler());

from(REST_ENDPOINT_URI)
.routeId("RestFulService")
.process(new MappingProcessor(new DemoRequestServiceImpl()));
}

}

8. Implement the Camel Processes (MappingProcessor).

Here, MappingProcessor implements the Camel Process. It takes the REST Impl instance and uses the reflection in the process method for it’s implementation as below.


package camel.process;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.component.cxf.common.message.CxfConstants;
public class MappingProcessor implements Processor {

private Class<?> beanClass;
private Object instance;

public MappingProcessor(Object obj) {
beanClass = obj.getClass();
instance = obj;
}

@Override
public void process(Exchange exchange) throws Exception {
String operationName = exchange.getIn().getHeader(CxfConstants.OPERATION_NAME, String.class);
Method method = findMethod(operationName,exchange.getIn().getBody(Object[].class));
try {
Object response = method.invoke(instance, exchange.getIn().getBody(Object[].class));
exchange.getOut().setBody(response);
} catch (InvocationTargetException e) {
throw (Exception) e.getCause();
}
}

private Method findMethod(String operationName, Object[] parameters)throws SecurityException, NoSuchMethodException {
return beanClass.getMethod(operationName,getParameterTypes(parameters));
}

private Class<?>[] getParameterTypes(Object[] parameters) {
if (parameters == null) {
return new Class[0];
}
Class<?>[] answer = new Class[parameters.length];
int i = 0;
for (Object object : parameters) {
answer[i] = object.getClass();
i++;
}
return answer;
}

}

9. Creating the Rest IMPL classes.

Here, this is the main IMPL classes of the REST implementation. Here the paths are defined by using the @Path annotation. Here, the main path is defined as the /hotelservice. So, each method defined in this class must be called starting from http://localhost:9003/rest/hotelservice. Each implementation methods is defined with dedicated paths.

Here,  getAvailabilityResults(Long id) will be called as http://localhost:9003/rest/hotelservice./hotels/10. Here this methods takes the Long path parameter as 10. And it will be forwarded to the concrete implementation in DemoRequestServiceImpl.java class. Here, getAvailabilityResults is defined as a GET method and getSearhResults(String request) as a POST methos.

a. IDemoRequestService.java

package rs;

import javax.jws.WebParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/hotelService")
@Consumes("application/json")
@Produces(MediaType.APPLICATION_JSON)
public interface IDemoRequestService {

 @GET
 @Path("/hotels/{id}")
 @Produces(MediaType.APPLICATION_JSON)
 Response getAvailabilityResults(@PathParam("id") Long id); 

 @POST
 @Path("/search")
 @Produces(MediaType.APPLICATION_JSON)
 String getSearhResults(@WebParam(name="request") String request); 

}

b. DemoRequestServiceImpl.java

package rs;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DemoRequestServiceImpl implements IDemoRequestService {

 final Logger logger = LoggerFactory.getLogger(DemoRequestServiceImpl.class);

 @Override
 public String getSearhResults(String request) {

 logger.info("getSearhResults().request : " + request);

 return "Hello request " + request;
 }

 @Override
 public Response getAvailabilityResults(Long id){

 logger.info("getSearhResults().Long : " + id);
 return Response.ok("Hello request ID :"+id).status(Status.OK).build();
 }

}

9. Final Folder structure.

3-final-folder-structure

10. Build the project by running the pom.xml through Maven.

Here, I have used clean install package as the maven goal. I executed the maven goals within the eclipse.

11. Deploy the demo.restapi-1.0.0.war in a web container like tomcat.

Here, I used the tomcat8 to deploy the REST service. When tomcat is starting, router is deployed automatically. Then the specified requests (GET ot POST) we are sent to the END POINT URI will be taken to process by the router.

12. Test the GET method.

Here, we can test the GET method using the browser as follows

Hit http://localhost:9003/rest/hotelService/hotels/17 in the browser and get the response as “Hello request ID :17”

13. Test the POST method

– Await !!!

Advertisements

Written by Namal Fernando

June 29, 2014 at 5:18 pm

Ruth's Reflections

Contemplations from quakey quirky Christchurch

TED Blog

The TED Blog shares interesting news about TED, TED Talks video, the TED Prize and more.

Ziplok

Learn and discover simple things

Meihta Dwiguna Saputra's Knowledge Base

~In learning you will teach and in teaching you will (re)learn~

The Java Blog

Thoughts, tips and tricks about the Java programming language

Sparkles

that were shone when I got tempered!