My Works

Full Stack with Apache Camel.

Apache camel is a java framework for systems integrations that allows developer to write code in an English-like expression using Enterprise Integration Patterns concepts. Apache Camel enables cleaner, easier to understand code leading to less work, less bugs and easier maintenance when compared to traditional systems integrations that requires bolerplate code, repetitive tasks and templating. Camel provides an domain-specific language(DSL) for defining logic that is adapted to Java,Groovy and Scala and frameworks like Spring ,OSGI Blueprint so that the developers can specify the desired technologies without getting lost in the boilerplate code required to use that technologies.

We are going to look at creating a fullstack with Apache camel. Each of the module would be deployable based on the microservice feature of being independently deployable.The Business processing and Database are independent Rest server.The database like module would be available as rest service, the middle tier processing is also available as Rest Server, the Front End does the interaction using these Rest servers. This example provides a list of Fireworks in a Like Database which is available as RestServer based on Apache Camel RestConfiguration using Undertow component.The Front End sends request to GetAll Fireworks and update a Firework using HttpClient based on Apache Camel HTTP4 component. Front End also aggregates the Response for GetAll Fireworks and update a Firework.The Front End sends the request to business logic Processing Rest Service based on RestConfiguration of Apache Camel Restlet Component called the RLRestServer. The RLRestServer processes the request and sends it to Database using Restlet and Processes the Response in this a XML using XQuery scripts for removing the namespace, further more Groovy scripts change the XML to Required Response Message. So in a Polyglot manner different desired technologies are being used without getting lost in the boilerplate code required to use the technologies.

  1. Create Parent Project with Modules.
  2. Create Rest Server acting as a service for a database.
  3. Create Rest Server with Apache Camel Integrating Front End and Back End.
  4. Create Front End that interacts with the Rest Servers Using Apache Camel.
  5. Execute the tests and check the data.
  6. Download the example.

In this example here provide a Front End which requests for list of FireWorks and also update Firework details in the Database like FireWorksService Objects

1.Create Parent Project with Modules.

Create a project folder FullStackCamelWorks containing a parent POM. Add DbRestServer, FECamelWorks and RLRestServer as modules in the Parent POM. Please Refer this link for some more information on Multi Module Project.


<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/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>MicroservicesWithCamel</groupId>
<artifactId>FullStackCamelWorks</artifactId>
<version>1.0</version>
<packaging>pom</packaging>

<modules>
<module>DBRestServer</module>
<module>RLRestServer</module>
<module>FECamelWorks</module>
</modules>

<reporting>

<plugins>

<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.3</version>
</plugin>

<plugin>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.16</version>
</plugin>

</plugins>

</reporting>

</project>


2.Create Rest Server acting as a service for a database.

Create a module DBRestServer with Project dependencies described as JDK 1.8,camel-core.jar,camel-undertow.jar, camel-swagger-java.jar,spring-webmvc.jar,spring-expression.jar,javax.servlet-api.jar,camel-test.jar,camel-http.jar are the ones that would be needed. The common, logging and junit jars also needed these dependencies are available in the downloaded example. The pom file dependencies are listed below.



<properties>
<spring.version>4.3.3.RELEASE</spring.version>
<camel.version>2.17.1</camel.version>
<log.version>1.7.0</log.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<!--Camel dependencies -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel.version}</version>
</dependency>

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

<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-swagger-java</artifactId>
<version>${camel.version}</version>
</dependency>
<!--end Camel dependencies -->

<!--Spring Mvc dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>

<!--end SpringMvc dependencies -->


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

<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-http</artifactId>
<version>${camel.version}</version>
<scope>test</scope>
</dependency>


Front End sends requests to fetch FireWorks details therefore the required objects are provided.

Create FireWork, FireWorks, FireWorksService objects and DbRestServerUtility.


@XmlRootElement(name = "firework",namespace="urn:firework")
public class FireWork {

private int id;
private String name;
private String category;
private String description;

public FireWork() {
}
.....


@XmlRootElement(name = "fireworks",namespace="urn:fireworks")
@XmlAccessorType(XmlAccessType.FIELD)
public class FireWorks {

@XmlElement(name = "firework",namespace="urn:firework")
private List<FireWork> fireworks = new ArrayList<FireWork>();

.....
.....


public class FireWorksService {

private static final Logger log = LoggerFactory.getLogger(FireWorksService.class);

private final Map<String, FireWork> fireworksData = new TreeMap<String, FireWork>();

public FireWorksService() {
fireworksData.put("123", new FireWork(123, "Sparklers", "Sparkler200", "Long Sparklers"));
fireworksData.put("456", new FireWork(456, "Rockets", "Rocket Absolute", "Goes up with sound"));
fireworksData.put("789", new FireWork(789, "Fountains", "Small Fountain", "Lasts for two minutes"));
fireworksData.put("265", new FireWork(265, "Swirls", "Ground Swirls", "Rotates with Coloured Sparkles"));
}

public FireWork getFireWork(String id) {
return fireworksData.get(id);
}

public Collection<FireWork> listFireWorks() {
return fireworksData.values();
}

public FireWork updateFireWork(FireWork firework) {
log.info("Updating firework at FireWorksService");
return fireworksData.put("" + firework.getId(), firework);
}

public FireWork findFireWorkById(String Id) {
return fireworksData.get(Id);
}
}




public class DbRestServerUtility {
private static final Logger log = LoggerFactory.getLogger(DbRestServerUtility.class);

public static void fireWorksCollectionToXML(FireWorks fireworks, StringWriter stringWriter) {

try {

JAXBContext jaxbContext = JAXBContext.newInstance(FireWorks.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

jaxbMarshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",
new NamespacePrefixMapper() {
@Override
public String getPreferredPrefix(String namespaceuri, String suggestion,boolean requireprefix) {

String prefix = "";

if ("urn:fireworks".equalsIgnoreCase(namespaceuri)) {
prefix = "fws";
}

if ("urn:firework".equalsIgnoreCase(namespaceuri)) {
prefix = "fw";
}

return prefix;
}});

jaxbMarshaller.marshal(fireworks, stringWriter);

} catch (PropertyException e) {
log.info("Error", e);
} catch (JAXBException e) {
log.info("Error", e);
}
}
....
....
}


The Camel Context used by the Rest Server would be started along with the added camel routes when the WebServer has started the DbRestServer context path using the DbServerCamelListener.

Create DbServerCamelListener.


public final class DbServerCamelListener implements ServletContextListener {

private static final Logger log = LoggerFactory.getLogger(DbServerCamelListener.class);
private static final CamelContext context = new DefaultCamelContext();

public static CamelContext getContext() {
return context;
}

@Override
public void contextDestroyed(ServletContextEvent arg0) {

log.info("Finished with the camel at DBRestServer");

try {
context.stop();
} catch (Exception e) {
log.info("Exception at DbServerCamelListener", e);
}

}

@Override
public void contextInitialized(ServletContextEvent arg0) {

log.info("Started camel Context camel at DBRestServer");

try {
context.addRoutes(new DbServerRoute());
} catch (Exception e) {
log.info("Exception at DbServerCamelListener", e);
}

try {
context.start();
} catch (Exception e) {
log.info("Exception at DbServerCamelListener", e);
}

}
}


The Database is served as Rest Server using Apache Camel RestConfiguration and Routes and Processors to help process the received requests.Undertow is the RestConfiguration component used to serve as Rest Server for the Database. Please Refer documentation on Camel Rest DSL.

Create Routes and Processor for the Rest Server using Undertow camel component. Please Refer documentation on Camel Undertow and Undertow documentation.


public class DbServerRoute extends RouteBuilder {

public static final String CAMEL_ENDPOINT_DIRECT_DBUPDATEFIREWORK = "direct:dbupdatefirework";
public static final String CAMEL_ENDPOINT_DIRECT_DBFIREWORKSCOLLECTION = "direct:dbfireworkscollection";
public static final int DBRESTSERVER_PORT_NUMBER_8181 = 8181;
public static final String DOMAIN_LOCALHOST = "localhost";

public static final String CAMEL_ENDPOINT_DIRECT_ERROR = "direct:error";
public static final String DBUPDATEFIREWORK = "dbupdatefirework";
public static final String DBFIREWORKSCOLLECTION = "dbfireworkscollection";
public static final String DB_ROUTE_STATUS = "DbRouteStatus";

@Override
public void configure() throws Exception {

onException(Exception.class).onWhen(header(DB_ROUTE_STATUS).contains(DBFIREWORKSCOLLECTION))
.to(CAMEL_ENDPOINT_DIRECT_ERROR).handled(true).end();
onException(Exception.class).onWhen(header(DB_ROUTE_STATUS).contains(DBUPDATEFIREWORK))
.to(CAMEL_ENDPOINT_DIRECT_ERROR).handled(true).end();
onException(Exception.class).handled(true)
.transform().constant("Sorry DBRestServer Could Not Process Due to Errors").end();

restConfiguration().component("undertow").host(DOMAIN_LOCALHOST)
.port(DBRESTSERVER_PORT_NUMBER_8181).bindingMode(RestBindingMode.auto)
.componentProperty("matchOnUriPrefix", "true")
.dataFormatProperty("prettyPrint", "true").apiContextPath("/api-doc")
.apiProperty("api.title", "User API").apiProperty("api.version", "1.2.3")
.apiProperty("cors", "true");

rest("/fireworks/getAll").description("Servlet for Get All Fireworks").get()
.description("Get Request of Servlet for Get All Fireworks and It Produces XML")
.outType(String.class).produces("appication/xml").route()
.to(CAMEL_ENDPOINT_DIRECT_DBFIREWORKSCOLLECTION).endRest()
.post().description("POST Request of Servlet for Get All Fireworks and It Produces XML")
.outType(String.class).produces("appication/xml").route()
.to(CAMEL_ENDPOINT_DIRECT_DBFIREWORKSCOLLECTION);

rest("/fireworks/updatefirework").description("Servlet for Update Firework").post()
.description("Get Request of Servlet for Update Firework and It Produces XML")
.outType(String.class).produces("text/plain").route()
.to(CAMEL_ENDPOINT_DIRECT_DBUPDATEFIREWORK);

from(CAMEL_ENDPOINT_DIRECT_DBFIREWORKSCOLLECTION)
.setHeader(DB_ROUTE_STATUS, constant(DBFIREWORKSCOLLECTION))
.process(new FireWorksListProcessor()).log("Message ${body}");

from(CAMEL_ENDPOINT_DIRECT_DBUPDATEFIREWORK)
.setHeader(DB_ROUTE_STATUS, constant(DBUPDATEFIREWORK))
.process(new FireWorksUpdateProcessor()).log("Message ${body}");

from(CAMEL_ENDPOINT_DIRECT_ERROR).process(new DbServerErrorHandlerProcessor()).log(
"Message ${body}");

}
}


Create DbServerErrorHandlerProcessor,FireWorksListProcessor and FireWorksUpdateProcessor.



public class FireWorksListProcessor implements Processor {
private static final Logger log = LoggerFactory.getLogger(FireWorksListProcessor.class);

@Override
public void process(Exchange exchange) throws Exception {

log.info("Processing with FireWorksListProcessor");
StringWriter stringWriter = new StringWriter();
FireWorksService dataService = new FireWorksService();
FireWorks fireworks = new FireWorks();
fireworks.setFireworks(new ArrayList<FireWork>(dataService.listFireWorks()));
DbRestServerUtility.fireWorksCollectionToXML(fireworks, stringWriter);
exchange.getIn().setBody(stringWriter.toString());


}
}



public class FireWorksUpdateProcessor implements Processor {
private static final Logger log = LoggerFactory.getLogger(FireWorksUpdateProcessor.class);

@Override
public void process(Exchange exchange) throws Exception {

log.info("Processing with FireWorksUpdateProcessor");
StringWriter stringWriter = new StringWriter();
FireWorksService dataService = new FireWorksService();

String source = exchange.getIn().getBody(String.class);
log.info("The source is " + source);
String id = StringUtils.substringBetween(source, "Update:", "{");
log.info("The id  is " + id);
String updateDescription = StringUtils.substringBetween(source, "{", "}");
log.info("The change  is " + updateDescription);

String description = (updateDescription.contains(",")) ? StringUtils.substringBetween(source, "description:", ",") : StringUtils.removeStart(updateDescription, "description:");
FireWork firework = dataService.findFireWorkById(id);

firework.setDescription(description);
dataService.updateFireWork(firework);

DbRestServerUtility.fireWorksToXML(dataService.getFireWork(String.valueOf(firework.getId())), stringWriter);
exchange.getIn().setBody(stringWriter.toString());

}
}


The Processor which handles the messages on Exception in the routes is provided by the DbServerErrorHandlerProcessor.


public class DbServerErrorHandlerProcessor implements Processor {

public static final String DB_SERVER_ERROR_WHILE_PROCESSING_REQUEST = "DbServer Error While Processing Request";
public static final String DB_SERVER_ERROR_WHILE_UPDATING_A_FIRE_WORK = "DbServer Error While Updating a FireWork";

public static final String DB_SERVER_ERROR_WHILE_FETCHING_LIST_OF_FIRE_WORKS = "DbServer Error While fetching List of  FireWorks";
public static final Logger log = LoggerFactory.getLogger(DbServerErrorHandlerProcessor.class);

@Override
public void process(Exchange exchange) throws Exception {

Exception dbexception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
log.error("DbServerErrorHandlerProcessor Logging:", dbexception);

String DbRestServerStatus = exchange.getIn().getHeader(DB_ROUTE_STATUS, String.class);

if (DbRestServerStatus.equalsIgnoreCase(DBFIREWORKSCOLLECTION)) {
errorSetBody(exchange, DB_SERVER_ERROR_WHILE_FETCHING_LIST_OF_FIRE_WORKS);
} else if (DbRestServerStatus.equalsIgnoreCase(DBUPDATEFIREWORK)) {
errorSetBody(exchange, DB_SERVER_ERROR_WHILE_UPDATING_A_FIRE_WORK);
errorSetBody(exchange, exchange.getIn().getBody(String.class));
} else {

errorSetBody(exchange, DB_SERVER_ERROR_WHILE_PROCESSING_REQUEST);

if (dbexception != null) {
errorSetBody(exchange, dbexception.getMessage());
}

}
}

private void errorSetBody(Exchange exchange, String newBody) {
String body = exchange.getIn().getBody(String.class);
if (newBody != null) {
body = (StringUtils.isNotBlank(body)) ? body + System.getProperty("line.separator")
+ newBody : newBody;
}
exchange.getIn().setBody(body);
}
}


Create SpringMVC WebConfiguration for the Rest Server.

Create DbServerMvcContextConfiguration,DbServerViewConfiguration and DbServerWebInitializer.


@Configuration
@ComponentScan(basePackages = { "org.srinivas.siteworks.dbrestserver.webconfig" })
public class DbServerMvcContextConfiguration extends WebMvcConfigurerAdapter {

@Override
public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
}
}



public class DbServerViewConfiguration {
private static final Logger logger = LoggerFactory.getLogger(DbServerViewConfiguration.class);

@Bean
public ViewResolver dbviewResolver() {
logger.info("ViewConfiguration dbviewResolver()");
return new ContentNegotiatingViewResolver();
}
}


The WebApplicationContext registers the DbServerCamelListener and ContextLoaderListener.


public class DbServerWebInitializer implements WebApplicationInitializer {
private static final Logger logger = LoggerFactory.getLogger(DbServerWebInitializer.class);

@Override
public void onStartup(ServletContext container) {
logger.info("Started to pickup the annotated classes at DbServerWebInitializer");
startServlet(container);
}

private void startServlet(final ServletContext container) {

WebApplicationContext dispatcherContext = registerContext(DbServerMvcContextConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);

container.addListener(new ContextLoaderListener(dispatcherContext));
container.addListener(new DbServerCamelListener());

ServletRegistration.Dynamic dispatcher;
dispatcher = container.addServlet("dispatcher", dispatcherServlet);

dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*");
}

private WebApplicationContext registerContext(final Class<?>... annotatedClasses) {
logger.info("Using AnnotationConfigWebApplicationContext createContext");
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(annotatedClasses);
return context;
}
}


Create Camel Test and Integration test for the DbServerRoute. Please Refer documentation on Camel Test and Camel Http.


public class DbServerRouteTest extends CamelTestSupport {

private static final Logger log = LoggerFactory.getLogger(DbServerRouteTest.class);

@Produce(uri = "direct:start")
protected ProducerTemplate template;

@Override
public boolean isCreateCamelContextPerClass() {
	   return true;
}

@Test
public void testDbRestServerRoutegetALL() throws Exception {
String result = template.requestBody("direct:dbfireworkscollection", null, String.class);
assertNotNull("Result is not Null", result);
assertTrue("Result contains", result.contains("<fws:fireworks"));
}

....
....

@Override
protected RouteBuilder createRouteBuilder() {
return new DbServerRoute();
}
}



public class DbServerRouteIntegrationTest {
private static final Logger log = LoggerFactory.getLogger(DbServerRouteIntegrationTest.class);
private final static int port = 8181;

private static final String FIREWORKS_COLLECTIONS_URL = "http://localhost:" + port + "/fireworks/getAll";
private static final String FIREWORK_UPDATE_URL = "http://localhost:" + port + "/fireworks/updatefirework";

RouteBuilder getALLRouteClient;
RouteBuilder updateFireWorkRouteClient;

@Before
public void setUp() throws Exception {

getALLRouteClient = new RouteBuilder() {
public void configure() {
from("direct:a").setHeader(Exchange.HTTP_METHOD, constant("GET"))
.to(FIREWORKS_COLLECTIONS_URL);
}};

updateFireWorkRouteClient = new RouteBuilder() {
public void configure() {
from("direct:b").transform()
.constant("Update:789{description:fountains colour}")
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
.to(FIREWORK_UPDATE_URL);
}};

}

@After
public void teardown() throws Exception {
getALLRouteClient = null;
updateFireWorkRouteClient = null;
}

@Test
public void updateFireWorkTest() throws Exception {
CamelContext context = new DefaultCamelContext();
context.addRoutes(updateFireWorkRouteClient);

ProducerTemplate template = context.createProducerTemplate();
context.start();

String result = (String) template.requestBody("direct:b", "Update:789{description:fountains colour}", String.class);

log.info("The result is" + result);
context.stop();

assertNotNull("Result is not Null", result);
assertTrue("Result contains", result.contains("<fw:firework"));
}
.....
.....

}
}


3.Create Rest Server with Apache Camel Integrating Front End and Back End.

Rest Server based on Apache camel takes request from Front End and processes request and sends it to database, then processes response.The Rest Server uses the Restlet component of RestConfiguration.In this module the response processing is a polyglot processing using XQuery and Groovy scripts to demonstrate that different technologies can be used within a same Route.

Create a module RLRestServer with Project dependencies described as JDK 1.8,camel-core.jar,camel-restlet.jar, camel-swagger-java.jar,camel-groovy.jar,camel-saxon.jar,camel-script.jar,spring-webmvc.jar,spring-expression.jar,javax.servlet-api.jar,camel-test.jar,camel-http.jar are the ones that would be needed. The common, logging and junit jars also needed these dependencies are available in the downloaded example.The pom file dependencies are listed below.


<properties>
<spring.version>4.3.3.RELEASE</spring.version>
<camel.version>2.17.1</camel.version>
<log.version>1.7.0</log.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>


<!--Camel dependencies -->

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

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

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

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

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

<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-script</artifactId>
<version>${camel.version}</version>
</dependency>
<!--end Camel dependencies -->

<!--Spring Mvc dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>

<!--end SpringMvc dependencies -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test</artifactId>
<version>${camel.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-http</artifactId>
<version>${camel.version}</version>
<scope>test</scope>
</dependency>


The Camel Context used by the Rest Server would be added with camel routes and started while the WebServer starting the RLRestServer context path using the RLRestServerCamelListener.

Create RLRestServerCamelListener.



public final class RLRestServerCamelListener implements ServletContextListener {

private static final Logger log = LoggerFactory.getLogger(RLRestServerCamelListener.class);
private static final CamelContext context = new DefaultCamelContext();

public static CamelContext getContext() {
return context;
}

@Override
public void contextDestroyed(ServletContextEvent arg0) {
log.info("Camel Context stopped at RLRestserver");

try {
context.stop();
} catch (Exception e) {
log.info("Exception at RLRestServerCamelListener", e);
}
}

@Override
public void contextInitialized(ServletContextEvent arg0) {
log.info("Camel Context started at RLRestserver");

try {
context.addRoutes(new RLRestServerRoute());
} catch (Exception e) {
log.info("Exception at RLRestServerCamelListener", e);
}

try {
context.start();
} catch (Exception e) {
log.info("Exception at RLRestServerCamelListener", e);
}

}
}


The RLRestServer module is served as Rest Server using Apache Camel RestConfiguration and Routes and Processors to help process the received requests.Restlet is the RestConfiguration component used to serve as Rest Server for the RLRestServer.

Create Routes and Processor for the Rest Server RestConfiguration component Restlet. Please Refer documentation on Camel Restlet and Restlet.


public class RLRestServerRoute extends RouteBuilder {

public static final String CAMEL_ENDPOINT_DIRECT_START = "direct:start";
private static final String CAMEL_ENDPOINT_DIRECT_RLFIREWORKSCOLLECTION = "direct:RLfireworkscollection";
public static final String CAMEL_ENDPOINT_DIRECT_RLUPDATEFIREWORK = "direct:RLupdatefirework";
public static final String CAMEL_ENDPOINT_DIRECT_RLRESPONSEPROCESS = "direct:RLresponseprocess";

public static final String CAMEL_ENDPOINT_DIRECT_ERROR = "direct:error";
public static final int PORT_NUMBER_8180 = 8180;
public static final String DOMAIN_LOCALHOST = "localhost";
public static final String RLRESPONSEPROCESS = "RLresponseprocess";

public static final String RLUPDATEFIREWORK = "RLupdatefirework";
public static final String RLFIREWORKSCOLLECTION = "RLfireworkscollection";
public static final String RL_ROUTE_STATUS = "RLRouteStatus";

@Override
public void configure() throws Exception {

onException(Exception.class).onWhen(header(RL_ROUTE_STATUS).contains(RLFIREWORKSCOLLECTION))
.handled(true).to(CAMEL_ENDPOINT_DIRECT_ERROR).end();
onException(Exception.class).onWhen(header(RL_ROUTE_STATUS).contains(RLUPDATEFIREWORK))
.handled(true).to(CAMEL_ENDPOINT_DIRECT_ERROR).end();
onException(Exception.class).onWhen(header(RL_ROUTE_STATUS).contains(RLRESPONSEPROCESS))
.to(CAMEL_ENDPOINT_DIRECT_ERROR).handled(true).end();
onException(Exception.class).handled(true)
.transform().constant("Sorry RLRestServer Could Not Process Due to Errors").end();

restConfiguration().component("restlet").host(DOMAIN_LOCALHOST).port(PORT_NUMBER_8180)
.bindingMode(RestBindingMode.auto).dataFormatProperty("prettyPrint", "true")
.apiContextPath("/api-doc").apiProperty("api.title", "User API")
.apiProperty("api.version", "1.2.3").apiProperty("cors", "true");

rest("/fireworks/getAll").description("Restlet for Get All FireWorks").get()
.description("Get Request of Restlet for Get All FireWorks and It Produces XML")
.outType(String.class).produces("text/plain").route()
.to(CAMEL_ENDPOINT_DIRECT_RLFIREWORKSCOLLECTION).endRest().post()
.description("POST Request of Restlet for Get All FireWorks and It Produces XML")
.outType(String.class).produces("text/plain").route()
.to(CAMEL_ENDPOINT_DIRECT_RLFIREWORKSCOLLECTION);

rest("/fireworks/updatefirework").description("Restlet for Update Firework").post()
.description("Post Request of Restlet for Update Firework and It Produces XML")
.outType(String.class).produces("text/plain").route().to(CAMEL_ENDPOINT_DIRECT_RLUPDATEFIREWORK);

from(CAMEL_ENDPOINT_DIRECT_START).choice().when(body().isEqualToIgnoreCase("fireworks/getAll"))
.to("restlet:http://localhost:8180/fireworks/getAll?restletMethods=GET")
.when(body().isEqualToIgnoreCase("fireworks/updatefirework"))
.to("restlet:http://localhost:8180/fireworks/updatefirework?restletMethod=POST")
.otherwise().transform(simple("${body}: does not have a corresponding Restlet"))
.end();

from(CAMEL_ENDPOINT_DIRECT_RLFIREWORKSCOLLECTION)
.setHeader(RL_ROUTE_STATUS, constant(RLFIREWORKSCOLLECTION))
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
exchange.getIn().setHeader("org.restlet.http.headers",
new Series<Header>(Header.class));
}
}).to("restlet:http://localhost:8181/fireworks/getAll?restletMethods=GET")
.to(CAMEL_ENDPOINT_DIRECT_RLRESPONSEPROCESS).log("Message ${body}");

from(CAMEL_ENDPOINT_DIRECT_RLUPDATEFIREWORK)
.setHeader(RL_ROUTE_STATUS, constant(RLUPDATEFIREWORK))
.setHeader(HeaderConstants.HEADER_CONTENT_TYPE, constant(MediaType.TEXT_PLAIN))
.transform()
.simple("${in.header[fireworkupdatekey]}")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
exchange.getIn().setHeader("org.restlet.http.headers",
new Series<Header>(Header.class));
}
}).to("restlet:http://localhost:8181/fireworks/updatefirework?restletMethod=POST")
.log("Message in RLupdatefirework finsished to dbserver")
.to(CAMEL_ENDPOINT_DIRECT_RLRESPONSEPROCESS).log("Message ${body}");

from(CAMEL_ENDPOINT_DIRECT_RLRESPONSEPROCESS).setHeader(RL_ROUTE_STATUS, constant(RLRESPONSEPROCESS))
.log("Message in RLresponseprocess moving to xquery").convertBodyTo(String.class)
.to("xquery:removeNameSpaces.xqy").convertBodyTo(String.class)
.log("Message ${body}").setHeader("sequence")
.groovy("resource:classpath:Mygroovy.groovy");
from(CAMEL_ENDPOINT_DIRECT_ERROR).process(new RLRestServerErrorHandlerProcessor())
.log("Message ${body}");

}
}


The Response Processing starts removing the NameSpaces of the Response XML using XQuery script and adding camel-saxon dependency. Please Refer documentation on Camel XQuery.

removeNameSpaces.xqy.


declare function local:remove-namespaces($element as element()) as element() {
element { local-name($element) } {
for $att in $element/@*
return
attribute {local-name($att)} {$att},
for $child in $element/node()
return
if ($child instance of element())
then local:remove-namespaces($child)
else $child
}
};
let $check := (//*[local-name() = 'fireworks'])
let $request :=   if(empty ($check))
then
(//*[local-name() = 'firework'])
else
(//*[local-name() = 'fireworks'])
null
let $result := (local:remove-namespaces($request))
return $result


Further Response Processing is done by Processing the XML to required messages using Groovy Scripts backed by Apache Camel camel-groovy dependency.

Mygroovy.groovy.


import groovy.util.slurpersupport.NodeChild
import groovy.util.slurpersupport.NodeChildren
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil
def values = "${body}"
def response = new XmlSlurper().parseText(values)
def sb = new StringBuffer()
if(values.startsWith("<firework>")){
sb.append("The FireWorks Update");
sb.append(System.getProperty("line.separator"))
sb.append(response.id)
sb.append(":")
sb.append(" ")
sb.append(response.name)
sb.append(":")
sb.append(" ")
sb.append(response.description )
sb.append(System.getProperty("line.separator"))
}
else{
sb.append("The FireWorks Search Details");
sb.append(System.getProperty("line.separator"))
response.firework.each{ firework->
sb.append(firework.id)
sb.append(":")
sb.append(" ")
sb.append(firework.name)
sb.append(":")
sb.append(" ")
sb.append(firework.description )
sb.append(System.getProperty("line.separator"))
}

}
exchange.getIn().setBody(sb.toString());


The Processor which handles the messages on Exception in the routes is provided by the RLRestServerErrorHandlerProcessor.

Create RLRestServerErrorHandlerProcessor.


public class RLRestServerErrorHandlerProcessor implements Processor {

public static final String RL_REST_SERVER_ERROR_WHILE_PROCESSING_REQUEST = "RLRestServer Error While Processing Request";
public static final String RL_REST_SERVER_ERROR_WHILE_POST_PROCESSING_DB_RESPONSE = "RLRestServer Error While Post Processing DbResponse";

public static final String RL_REST_SERVER_ERROR_WHILE_UPDATING_A_FIRE_WORK = "RLRestServer Error While Updating a FireWork";
public static final String RL_REST_SERVER_ERROR_WHILE_FETCHING_LIST_OF_FIRE_WORKS = "RLRestServer Error While fetching List of  FireWorks";

private static final Logger log = LoggerFactory.getLogger(RLRestServerErrorHandlerProcessor.class);

@Override
public void process(Exchange exchange) throws Exception {

Exception rlexception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
log.error("RLRestServerErrorHandlerProcessor Logging:", rlexception);

String RLRestServerStatus = exchange.getIn().getHeader(RL_ROUTE_STATUS, String.class);

if (RLRestServerStatus.equalsIgnoreCase(RLFIREWORKSCOLLECTION)) {
errorSetBody(exchange, RL_REST_SERVER_ERROR_WHILE_FETCHING_LIST_OF_FIRE_WORKS);
} else if (RLRestServerStatus.equalsIgnoreCase(RLUPDATEFIREWORK)) {
errorSetBody(exchange, RL_REST_SERVER_ERROR_WHILE_UPDATING_A_FIRE_WORK);
} else if (RLRestServerStatus.equalsIgnoreCase(RLRESPONSEPROCESS)) {
log.info("Exception Body" + exchange.getIn().getBody(String.class));
errorSetBody(exchange, RL_REST_SERVER_ERROR_WHILE_POST_PROCESSING_DB_RESPONSE);
} else {

errorSetBody(exchange, RL_REST_SERVER_ERROR_WHILE_PROCESSING_REQUEST);

if (rlexception != null) {
errorSetBody(exchange, rlexception.getMessage());
}

}
}

private void errorSetBody(Exchange exchange, String newBody) {
String body = exchange.getIn().getBody(String.class);

if (newBody != null) {
body = (StringUtils.isNotBlank(body)) ? body + System.getProperty("line.separator") + newBody : newBody;
}

exchange.getIn().setBody(body);

}
}


Create SpringMVC WebConfiguration for the Restlet based Rest Server.

Create RLRestServerMvcContextConfiguration,RLRestServerViewConfiguration and RLRestServerWebInitializer.


@Configuration
@ComponentScan(basePackages = { "org.srinivas.siteworks.rlrestserver.webconfig" })
public class RLRestServerMvcContextConfiguration extends WebMvcConfigurerAdapter {

@Override
public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
}
}



public class RLRestServerViewConfiguration {
private static final Logger logger = LoggerFactory.getLogger(RLRestServerViewConfiguration.class);

@Bean
public ViewResolver rlviewResolver() {
logger.info("ViewConfiguration rlviewResolver()");
return new ContentNegotiatingViewResolver();
}
}


The WebApplicationContext registers the DbServerCamelListener and ContextLoaderListener.


public class RLRestServerWebInitializer implements WebApplicationInitializer {
private static final Logger logger = LoggerFactory.getLogger(RLRestServerWebInitializer.class);

@Override
public void onStartup(ServletContext container) {
logger.info("Started to pickup the annotated classes at RLRestServerWebInitializer");
startServlet(container);
}

private void startServlet(final ServletContext container) {
WebApplicationContext dispatcherContext = registerContext(RLRestServerMvcContextConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);

container.addListener(new ContextLoaderListener(dispatcherContext));
container.addListener(new RLRestServerCamelListener());

ServletRegistration.Dynamic dispatcher;
dispatcher = container.addServlet("dispatcher", dispatcherServlet);

dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/*");

}

private WebApplicationContext registerContext(final Class<?>... annotatedClasses) {
logger.info("Using AnnotationConfigWebApplicationContext createContext");
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(annotatedClasses);
return context;
}
}


Create RLRestServerController.


@RestController
public class RLRestServerController {
private static final Logger log = LoggerFactory.getLogger(RLRestServerController.class);

@RequestMapping(value = "/fireworks/getAll")
public void restPage(HttpServletRequest request, Writer writer) throws Exception {

log.info("RLRestServerController restPage RestPath:" + "fireworks/getAll");

ProducerTemplate template = RLRestServerCamelListener.getContext().createProducerTemplate();

String result = template.requestBody(CAMEL_ENDPOINT_DIRECT_START, "fireworks/getAll", String.class);

writer.write(result);
}

@RequestMapping(value = "/fireworks/updatefirework", method = RequestMethod.POST)
public void restUpdatePage(HttpServletRequest request, HttpServletResponse response, Writer writer) throws Exception {
log.info("RLRestserver RLRestServerController restUpdatePage");

String payload = IOUtils.toString(request.getReader());
ProducerTemplate template = RLRestServerCamelListener.getContext().createProducerTemplate();

String result = template.requestBodyAndHeader(CAMEL_ENDPOINT_DIRECT_START, "fireworks/updatefirework", "fireworkupdatekey", payload, String.class);

log.info("resultprint at RLRestserver" + result);
writer.write(result);
}
}


Create Camel Test and Integration test for the RLRestServerRoute.


public class RLRestServerRouteTest extends CamelTestSupport {
private static final Logger log = LoggerFactory.getLogger(RLRestServerRouteTest.class);

@Produce(uri = "direct:start")
protected ProducerTemplate template;

@Override
public boolean isCreateCamelContextPerClass() {
return true;
}

@Test
public void testRLRestServerRoutegetALL() throws Exception {

String str = "<fireworks><firework><id>123</id><name>Sparkler200</name></firework><firework><id>265</id><name>Ground Swirls</name></firework><firework><id>456</id><name>Rocket Absolute</name></firework><firework><id>789</id><name>Small Fountain</name></firework></fireworks>";
context.getRouteDefinitions().get(2).adviceWith(context, new AdviceWithRouteBuilder() {

@Override
public void configure() throws Exception {
weaveByToString(".*localhost:8181/fireworks/getAll.*").replace().transform(constant(str));
}
});

String result = template.requestBody("direct:start", "fireworks/getAll", String.class);

assertNotNull("Result is not Null", result);
assertTrue("Result contains", result.contains("FireWorks Search"));
}
.....
......
@Override
protected RouteBuilder createRouteBuilder() {
return new RLRestServerRoute();
}



public class RLRestServerRouteIntegrationTest {

private static final Logger log = LoggerFactory.getLogger(RLRestServerRouteIntegrationTest.class);

private final static int port = 9091;
private static final String FIREWORKS_COLLECTIONS_URL = "restlet:http://localhost:" + port + "/RLRestServer/fireworks/getAll?restletMethods=GET";
private static final String FIREWORK_UPDATE_URL = "restlet:http://localhost:" + port + "/RLRestServer/fireworks/updatefirework?restletMethod=POST";

RouteBuilder getALLRouteClient;
RouteBuilder updateFireWorkRouteClient;

@Before
public void setUp() throws Exception {

getALLRouteClient = new RouteBuilder() {
public void configure() {
from("direct:a").to(FIREWORKS_COLLECTIONS_URL);
}
};

updateFireWorkRouteClient = new RouteBuilder() {
public void configure() {
from("direct:b").setHeader(HeaderConstants.HEADER_CONTENT_TYPE, constant(MediaType.TEXT_PLAIN)).to(FIREWORK_UPDATE_URL);
}
};
}

@After
public void teardown() throws Exception {
getALLRouteClient = null;
updateFireWorkRouteClient = null;
}

@Test
public void updateFireWorkTest() throws Exception {

CamelContext context = new DefaultCamelContext();
context.addRoutes(updateFireWorkRouteClient);

ProducerTemplate template = context.createProducerTemplate();
context.start();

String result = (String) template.requestBody("direct:b", "Update:789{description:fountains colour}", String.class);

log.info("The result is" + result);
context.stop();

assertNotNull("Result is not Null", result);
assertTrue("Result contains", result.contains("fountains colour"));
}
.......

4.Create Front End that interacts with the Rest Servers Using Apache Camel.

Create a module FECamelWorks with Project dependencies described as JDK 1.8,camel-core.jar,camel-http4.jar,spring-webmvc.jar,spring-expression.jar,javax.servlet-api.jar,camel-test.jar,camel-http.jar are the ones that would be needed. The common,servlet, logging and junit jars also needed these dependencies are available in the downloaded example. The pom file dependencies are listed below.


<properties>
<spring.version>4.3.3.RELEASE</spring.version>
<camel.version>2.17.1</camel.version>
<log.version>1.7.0</log.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<!--Camel dependencies -->

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

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

<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-swagger-java</artifactId>
<version>${camel.version}</version>
</dependency>
<!--end Camel dependencies -->

<!--Spring Mvc dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>com.springsource.javax.servlet.jsp</artifactId>
<version>2.1.0</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>com.springsource.javax.servlet.jsp.jstl</artifactId>
<version>1.2.0</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<!--end SpringMvc dependencies -->

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

<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-http</artifactId>
<version>${camel.version}</version>
<scope>test</scope>
</dependency>


The Camel Context used by the module FECamelWorks would be added with camel routes and started while the WebServer starting FECamelWorks context path using the FECamelWorksCamelListener.

Create FECamelWorksCamelListener.


public final class FECamelWorksCamelListener implements ServletContextListener {

private static final Logger log = LoggerFactory.getLogger(FECamelWorksCamelListener.class);
private static final CamelContext context = new DefaultCamelContext();

public static CamelContext getContext() {
return context;
}

@Override
public void contextDestroyed(ServletContextEvent arg0) {

log.info("Camel Context being Stopped for FECamelWorks");

try {
context.stop();
} catch (Exception e) {
log.info("Exception at FECamelWorksCamelListener", e);
}

}

@Override
public void contextInitialized(ServletContextEvent arg0) {

log.info("Camel context being started at FeCamelworks");

try {
context.addRoutes(new FECamelWorksRoute());
} catch (Exception e) {
log.info("Exception at FECamelWorksCamelListener", e);
}

try {
context.start();
} catch (Exception e) {
log.info("Exception at FECamelWorksCamelListener", e);
}

}
}


Create Routes and Processor for interacting with Rest Servers using Http4 component of Apache camel. Please Refer documentation on Camel Http4.


public class FECamelWorksRoute extends RouteBuilder {

public static final String CAMEL_ENDPOINT_DIRECT_ERROR = "direct:error";
public static final String FEUPDATEFIREWORK = "FEupdatefirework";

public static final String FEFIREWORKSCOLLECTION = "FEfireworkscollection";
public static final String FE_ROUTE_STATUS = "FERouteStatus";

@Override
public void configure() throws Exception {

onException(Exception.class).onWhen(header(FE_ROUTE_STATUS)
.contains(FEFIREWORKSCOLLECTION)).to(CAMEL_ENDPOINT_DIRECT_ERROR).handled(true).end();

onException(Exception.class).onWhen(header(FE_ROUTE_STATUS)
.contains(FEUPDATEFIREWORK)).to(CAMEL_ENDPOINT_DIRECT_ERROR).handled(true).end();

onException(Exception.class).handled(true)
.transform().constant("Sorry FECameWorks Could Not Process Due to Errors").end();

from("direct:process")
.split(bodyAs(String.class).tokenize("&&"), new StringAggregationStrategy())
.choice()
.when(body().contains("getAll"))
.setHeader(FE_ROUTE_STATUS, constant(FEFIREWORKSCOLLECTION))
.setHeader(Exchange.HTTP_METHOD,
constant(org.apache.camel.component.http4.HttpMethods.GET))
.to("http4://localhost:8080/RLRestServer/fireworks/getAll")
.when(body().contains("Update:"))
.setHeader(FE_ROUTE_STATUS, constant(FEUPDATEFIREWORK))
.log("Message ${body}")
.setHeader(Exchange.HTTP_METHOD,
constant(org.apache.camel.component.http4.HttpMethods.POST))
.to("http4://localhost:8080/RLRestServer/fireworks/updatefirework")
.convertBodyTo(String.class).otherwise()
.transform(simple("${body}: does not have a corresponding Service")).end()
.convertBodyTo(String.class).log("Message ${body}").end().to("mock:result");
from(CAMEL_ENDPOINT_DIRECT_ERROR).process(new FECamelWorksErrorHandlerProcessor())
.log("Message ${body}");

}
}


The Processor which handles the messages on Exception in the routes is provided by the FECamelWorksErrorHandlerProcessor. Also FECamelWorks can execute more than one request String like that of to GetAll the fireworks and update firework details in one call. Although Requests are split while requesting but the response is aggregated by the Apache Camel with StringAggregationStrategy.

Create FECamelWorksErrorHandlerProcessor and StringAggregationStrategy.


public class FECamelWorksErrorHandlerProcessor implements Processor {

public static final String FE_CAMEL_WORKS_ERROR_WHILE_PROCESSING_REQUEST = "FECamelWorks Error While Processing Request";

public static final String FE_CAMEL_WORKS_ERROR_WHILE_UPDATING_A_FIRE_WORK = "FECamelWorks Error While Updating a FireWork";
public static final String FE_CAMEL_WORKS_ERROR_WHILE_FETCHING_LIST_OF_FIRE_WORKS = "FECamelWorks Error While fetching List of  FireWorks";

private static final Logger log = LoggerFactory.getLogger(FECamelWorksErrorHandlerProcessor.class);

@Override
public void process(Exchange exchange) throws Exception {

Exception feexception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);

log.error("FECamelWorksErrorHandlerProcessor Logging:", feexception);

String FECamelWorksStatus = exchange.getIn().getHeader(FE_ROUTE_STATUS, String.class);

if (FECamelWorksStatus.equalsIgnoreCase(FEFIREWORKSCOLLECTION)) {
errorSetBody(exchange, FE_CAMEL_WORKS_ERROR_WHILE_FETCHING_LIST_OF_FIRE_WORKS);
} else if (FECamelWorksStatus.equalsIgnoreCase(FEUPDATEFIREWORK)) {
errorSetBody(exchange, FE_CAMEL_WORKS_ERROR_WHILE_UPDATING_A_FIRE_WORK);
} else {

errorSetBody(exchange, FE_CAMEL_WORKS_ERROR_WHILE_PROCESSING_REQUEST);

if (feexception != null) {
errorSetBody(exchange, feexception.getMessage());
}

}
}

private void errorSetBody(Exchange exchange, String newBody) {

String body = exchange.getIn().getBody(String.class);

if (newBody != null) {
body = (StringUtils.isNotBlank(body)) ? body + System.getProperty("line.separator") + newBody : newBody;
}

exchange.getIn().setBody(body);

}
}



public class StringAggregationStrategy implements AggregationStrategy {

private static final Logger log = LoggerFactory.getLogger(StringAggregationStrategy.class);

@Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {

if (oldExchange == null) {
return newExchange;
}

String oldBody = oldExchange.getIn().getBody(String.class);
String newBody = newExchange.getIn().getBody(String.class);

oldExchange.getIn().setBody(oldBody + "+" + newBody);
log.info("Aggregated using StringAggregationStrategy");

return oldExchange;
}
}


Create SpringMVC WebConfiguration for the Front end.

Create FECamelWorksMvcContextConfiguration,FECamelWorksViewConfiguration and FECamelWorksWebApplicationInitializer.


@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "org.srinivas.siteworks.fecamelworks.webconfig" })
public class FECamelWorksMvcContextConfiguration extends WebMvcConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(FECamelWorksMvcContextConfiguration.class);

@Override
public void configureDefaultServletHandling(final DefaultServletHandlerConfigurer configurer) {
logger.info("FECamelWorksMvcContextConfiguration WebMvcContextConfiguration: configureDefaultServletHandling Method");
configurer.enable();
}
}



@Configuration
public class FECamelWorksViewConfiguration {
private static final Logger logger = LoggerFactory.getLogger(FECamelWorksViewConfiguration.class);

@Bean
public ViewResolver feviewResolver() {
logger.info("ViewConfiguration feviewResolver()");
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setOrder(1);
viewResolver.setPrefix("/WEB-INF/displays/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}


The WebApplicationContext registers the FECamelWorksCamelListener and ContextLoaderListener.


public class FECamelWorksWebApplicationInitializer implements WebApplicationInitializer {
private static final Logger logger = LoggerFactory.getLogger(FECamelWorksWebApplicationInitializer.class);

@Override
public void onStartup(ServletContext container) {
logger.info("Started to pickup the annotated classes at FECamelWorksWebApplicationInitializer");
startServlet(container);
}

private void startServlet(final ServletContext container) {

WebApplicationContext dispatcherContext = registerContext(FECamelWorksMvcContextConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);

container.addListener(new ContextLoaderListener(dispatcherContext));
container.addListener(new FECamelWorksCamelListener());

ServletRegistration.Dynamic dispatcher;
dispatcher = container.addServlet("dispatcher", dispatcherServlet);

dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("*.mvc");
}

private WebApplicationContext registerContext(final Class<?>... annotatedClasses) {
logger.info("Using AnnotationConfigWebApplicationContext createContext");
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(annotatedClasses);
return context;
}
}


Create FECamelWorksController.



@Controller
public class FECamelWorksController {

public static final String HTML_BREAK_TAG = "<br/>";
private static final String NEWLINE_REGEX = "\\r\\n|\\n";

private static final Logger log = LoggerFactory.getLogger(FECamelWorksController.class);

@RequestMapping(value = "/camelworks.mvc", method = RequestMethod.GET)
public String camelWorksPage(Model model) throws Exception {

log.info("CamelWorksController");
ProducerTemplate template = org.srinivas.siteworks.fecamelworks.webconfig.FECamelWorksCamelListener.getContext().createProducerTemplate();

String result = template.requestBody("direct:process", "getAll&&Update:789{description:fountains colour}", String.class);
result = result.replaceAll(NEWLINE_REGEX, HTML_BREAK_TAG);

log.info("camelWorksPage Result is" + result);

model.addAttribute("message", result);
return "camelworks";
}
}


Create Camel Test and Integration test for the FECamelWorks.


public class FECamelWorksRouteTest extends CamelTestSupport {

private static final Logger log = LoggerFactory.getLogger(FECamelWorksRouteTest.class);

@Produce(uri = "direct:start")
protected ProducerTemplate template;

@Override
public boolean isCreateCamelContextPerClass() {
return true;
}

@Test
public void testFECamelWorksRouteUpdateFireWork() throws Exception {
final String str = "<firework><category>Fountains</category><description>fountains colour</description><id>789</id><name>Small Fountain</name></firework>";

context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {

@Override
public void configure() throws Exception {

weaveByToString("To[http4://localhost:8080/RLRestServer/fireworks/updatefirework]").replace().transform(constant(str));

}
});.Execute the tests and check the data.

String result = template.requestBody("direct:process", "Update:789{description:fountains colour}", String.class);
log.info("result is" + result);

assertNotNull("Result is not Null", result);
assertTrue("Result contains", result.contains("<firework>"));
}
......
.......
@Override
protected RouteBuilder createRouteBuilder() {
return new FECamelWorksRoute();
}



public class FECamelWorksRouteIntegrationTest {

private static final Logger log = LoggerFactory.getLogger(FECamelWorksRouteIntegrationTest.class);
private final static int port = 9090;

private static final String FIREWORKS_COLLECTIONS_URL = "http4://localhost:" + port + "/RLRestServer/fireworks/getAll";
private static final String FIREWORK_UPDATE_URL = "http4://localhost:" + port + "/RLRestServer/fireworks/updatefirework";

RouteBuilder getALLRouteClient;
RouteBuilder updateFireWorkRouteClient;

@Before
public void setUp() throws Exception {

getALLRouteClient = new RouteBuilder() {
public void configure() {
from("direct:a")
.setHeader(Exchange.HTTP_METHOD, constant(org.apache.camel.component.http4.HttpMethods.GET))
.to(FIREWORKS_COLLECTIONS_URL);
}};

updateFireWorkRouteClient = new RouteBuilder() {
public void configure() {
from("direct:b")
.setHeader(Exchange.HTTP_METHOD, constant(org.apache.camel.component.http4.HttpMethods.POST))
.setHeader("Content-Type", constant("text/plain"))
.to(FIREWORK_UPDATE_URL);
}};

}

@After
public void teardown() throws Exception {
getALLRouteClient = null;
updateFireWorkRouteClient = null;
}


@Test
public void updateFireWorkTest() throws Exception {

CamelContext context = new DefaultCamelContext();
context.addRoutes(updateFireWorkRouteClient);

ProducerTemplate template = context.createProducerTemplate();
context.start();

String result = (String) template.requestBody("direct:b", "Update:789{description:fountains colour}", String.class);
log.info("The result is" + result);
context.stop();

assertNotNull("Result is not Null", result);
assertTrue("Result contains", result.contains("fountains colour"));
}
.....
.....

5.Execute the tests and check the data.

Now the setup is ready to execute unit tests and integration tests for the modules DbRestServer,RLRestServer and FECamelWorks upon building the parent project FullStackCamelWorks from the commandline. Go to the path of parent project FullStackCamelWorks and use the command mvn clean install eclipse:clean eclipse:eclipse -Dwtpversion=2.0. This would build both Parent Project and the Modules within the parent Projects. To execute the Integration Tests from eclipse, have m2e plugin installed on your eclipse and create a m2 Maven Build configuration with Goal verify integration-test and execute the Integration Tests. Now the parent Project is Build along with Executions of Tests successfully.The java docs for the Project is generated by using the command mvn site from the parent folder FullStackCamelWorks. Check the site folder in the target directory and open index.html with a browser to start viewing Java docs. Each of the modules also have site folder in their target directory to help with their respective module javadocs. The swagger api-docs would be produced based on swagger configuration of the Apache Camel RestConfiguration. In the case DbRestServer check http://localhost:8181/api-doc/swagger.json and in the case of RLRestServer check http://localhost:8180/api-doc/swagger.yaml. Please Refer documentation on Camel Swagger-java.

The Result obtained After Pre Defined Requests is Executed displayed on Front End

The Result of Front End Requests

DbRestServer Integration Test Results

DbRestServer Test Results

RLRestServer Integration Test Results

RLRestServer Integration Test Results

FECamelWorks Integration Test Results

FECamelWorks Integration Test Results

Parent Project FullStackCamelWorks Build Results

Parent Project FullStackCamelWorks Build Results

FullStackCamelWorks site Summary

FullStackCamelWorks site Summary

JavaDocs View after site Summary

JavaDocs View after site Summary

Swagger api-docs for DbRestServer

Swagger api-docs for DbRestServer

6.Download the example.