Monday, August 31, 2015

JBoss Fuse ESB Example

INTRODUCTION

  • JBOSS Fuse is a open source Enterprise Service Bus (ESB).
  • It is a lightweight and modular integration platform.
The aim of this tutorial is to
  1. Create an application using Apache Camel
  2. Deploy the application into JBOSS Fuse ESB.

USECASE

  1. Enroll students for the Engineering Admission by various Colleges.
  2. Get the request as XML and copy it to a folder

SOFTWARES & TOOLS

  1. Eclipse IDE
  2. Java 1.8
  3. Maven

INSTALLATIONS

  1. Download JBoss Fuse ESB (jboss-fuse-6.2.0.redhat-133) from JBoss Official Website
  2. Extract the zip into your local : ~/softwares/jboss-fuse-6.2.0
  3. Install RESTClient in Chrome/Firefox browser.

IMPLEMENTATION

Step 1

Create a Maven project and copy the below into pom.xml

<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>com.jbr.jbossfuse</groupId>
<artifactId>FuseFirst</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>bundle</packaging>

<name>FuseFirst</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>3.2.0.RELEASE</spring.version>
<slf4j.version>1.7.10</slf4j.version>
<cxf.version>3.0.0</cxf.version>
<camel.version>2.13.0</camel.version>
<felix.maven.bundle.plugin.version>2.5.3</felix.maven.bundle.plugin.version>
</properties>

<build>
<defaultGoal>install</defaultGoal>
<plugins>
 <!-- Adding this plugin as an extension enables packaging=bundle (i.e.
  osgi bundle). This plugin will automatically add most of the OSGi meta-information
  to the generated OSGi bundle (jar file with extra entries in META-INF/MANIFEST.MF) -->
 <plugin>
  <groupId>org.apache.felix</groupId>
  <artifactId>maven-bundle-plugin</artifactId>
  <version>${felix.maven.bundle.plugin.version}</version>
  <extensions>true</extensions>
  <configuration>
   <instructions>
    <Import-Package>*</Import-Package>
    <Private-Package>
    </Private-Package>
   </instructions>
  </configuration>
 </plugin>
</plugins>
</build>
<dependencies>
<dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>3.8.1</version>
 <scope>test</scope>
</dependency>

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

<!-- SPRING -->
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>${spring.version}</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-spring</artifactId>
 <version>${camel.version}</version>
</dependency>
<dependency>
 <groupId>org.apache.camel</groupId>
 <artifactId>camel-test-spring</artifactId>
 <version>${camel.version}</version>
</dependency>
<dependency>
 <groupId>org.apache.camel</groupId>
 <artifactId>camel-jetty</artifactId>
 <version>${camel.version}</version>
</dependency>
<dependency>
 <groupId>org.apache.camel</groupId>
 <artifactId>camel-test</artifactId>
 <version>${camel.version}</version>
 <scope>test</scope>
</dependency>


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

<!-- CFX -->
<dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-frontend-simple</artifactId>
 <version>${cxf.version}</version>
</dependency>
<dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-frontend-jaxws</artifactId>
 <version>${cxf.version}</version>
</dependency>
<dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-databinding-aegis</artifactId>
 <version>${cxf.version}</version>
</dependency>
<dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-transports-local</artifactId>
 <version>${cxf.version}</version>
</dependency>
<dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-transports-http</artifactId>
 <version>${cxf.version}</version>
</dependency>
<dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-ws-security</artifactId>
 <version>${cxf.version}</version>
</dependency>

<!-- LOGGER -->
<dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-api</artifactId>
 <version>${slf4j.version}</version>
</dependency>
<dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-log4j12</artifactId>
 <version>${slf4j.version}</version>
 <scope>runtime</scope>
</dependency>
</dependencies>
</project>

Step 2

Create XML Schema for the usecase.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="EnrollmentDetails">
<xs:complexType>
 <xs:sequence>
  <xs:element name="CollegeName" type="xs:string"></xs:element>
  <xs:element name="CollegeCode" type="xs:string"></xs:element>
  <xs:element name="Student">
   <xs:complexType>
    <xs:sequence>
     <xs:element name="EnrollmentId" type="xs:int"></xs:element>
     <xs:element name="StudentName" type="xs:string"></xs:element>
     <xs:element name="Address" type="xs:string"></xs:element>
     <xs:element name="DateOfBirth" type="xs:string"></xs:element>
     <xs:element name="Age" type="xs:int"></xs:element>
     <xs:element name="Gender" type="xs:string"></xs:element>
     <xs:element name="ContactNumber" type="xs:int"></xs:element>
     <xs:element name="Email" type="xs:string"></xs:element>
     <xs:element name="EducationInfo">
      <xs:complexType>
       <xs:sequence>
        <xs:element name="Qualification" type="xs:string"></xs:element>
        <xs:element name="Grade" type="xs:string"></xs:element>
        <xs:element name="YearOfPassing" type="xs:int"></xs:element>
        <xs:element name="EntranceScore" type="xs:int"></xs:element>
       </xs:sequence>
      </xs:complexType>
     </xs:element>
    </xs:sequence>
   </xs:complexType>
  </xs:element>
 </xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Step 3

Create sample XML data.
<?xml version="1.0" encoding="UTF-8"?>

<EnrollmentDetails>
<CollegeName>MIT</CollegeName>
<CollegeCode>TN201</CollegeCode>
<Student>
<EnrollmentId>200</EnrollmentId>
<StudentName>Ranjith</StudentName>
<Address>Chennai</Address>
<DateOfBirth>15-May-1990</DateOfBirth>
<Age>25</Age>
<Gender>Male</Gender>
<ContactNumber>9600037466</ContactNumber>
<Email>ranjith@gmail.com</Email>
<EducationInfo>
 <Qualification>HSS</Qualification>
 <Grade>First</Grade>
 <YearOfPassing>2015</YearOfPassing>
 <EntranceScore>250</EntranceScore>
</EducationInfo>
</Student>

</EnrollmentDetails>

Step 4

Perform Marshalling and Unmarshalling using JAXB. Create Java Classes from the XSD.
  1. Create a new package (com.jbr.jbossfuse.beans)
  2. Right click the XSD file -> Generate - > JAXB Classes
  3. Select the newly Project: FuseExample -> Click Next
  4. Select the package: com.jbr.jbossfuse.beans -> Click Finish
  5. Now, the classes would be created in the package.

Step 5

Create Entry Point.
1. Create an Interface for Enrollment.
package com.jbr.jbossfuse;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import com.jbr.jbossfuse.beans.EnrollmentDetails;

@WebService
@Path("/")
@Consumes("application/xml")
@Produces("application/xml")
public interface Enrollment {

@WebMethod
@POST
@Path("/enrollStudent")
EnrollmentDetails enrollStudent(String enrollmentDetails);
}

2. Write an implementation for Enrollment.
package com.jbr.jbossfuse;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import com.jbr.jbossfuse.beans.EnrollmentDetails;

@WebService
@Path("/")
@Consumes("application/xml")
@Produces("application/xml")
public class NationalCollegeEnrollment implements Enrollment {

@WebMethod
@POST
@Path("/enrollStudent")
public EnrollmentDetails enrollStudent(String enrollmentDetails) {
throw new IllegalStateException("Invalid Request or Other Error. Check configuration");
}
}

Step 6

Creating a route.

package com.jbr.jbossfuse;

import org.apache.camel.builder.RouteBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EnrollmentRouter extends RouteBuilder {

 final public static Logger logger = LoggerFactory.getLogger(EnrollmentRouter.class);

 // Create a REST Service Request URL.
 private String restServiceUrl = "cxfrs://http://127.0.0.1:1834/enrollmentService?resourceClasses=com.jbr.jbossfuse.NationalCollegeEnrollment";

 // OUTPUT file location in the JBOSS FUSE ESB
 private String requestFilePath = "file://enrollment/request";

 /**
  * This method is default method of RouteBuilder class. It will be called only
  * ONCE when starting the FEATURE.
  */
 @Override
 public void configure() throws Exception {
   logger.info("Enter - EnrollmentRouter.confgure");

   /**
    * from(restServiceUrl) - Get the request from the REST Request.
    * routeId("EnrollmentRouterId") - is an id for the Route.
    * to("direct:EnrollStudent") - is and EndPoint, called by other process.
    */
   from(restServiceUrl).log("Saturday-Received message Inbound route of EnrollmentRouter")
       .routeId("EnrollmentRouterId").to("direct:EnrollStudent").end();

   /**
    * from("direct:EnrollStudent") - get the data from end point.
    * to(requestFilePath) - send the response to the folder.
    */
   from("direct:EnrollStudent").to(requestFilePath).end();

   logger.info("Exit - EnrollmentRouter.confgure");
 }
}

Step 7

Add resources as below
1. Create a folder "META-INF" under ~\FuseFirst\src\main\resources
2. Create a folder "spring" under ~\FuseFirst\src\main\resources\META-INF
3. Create a context file.

<?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:osgix="http://www.springframework.org/schema/osgi-compendium"
xmlns:ctx="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
         http://camel.apache.org/schema/spring
         http://camel.apache.org/schema/spring/camel-spring-2.15.0.xsd
         http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd
    http://www.springframework.org/schema/osgi-compendium
   http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd">

<camelContext trace="false" id="camelContext"
xmlns="http://camel.apache.org/schema/spring">
<routeBuilder ref="enrollmentRouter" />
</camelContext>

<bean id="enrollmentRouter" class="com.jbr.jbossfuse.EnrollmentRouter" />

</beans>

Step 8

Build the Maven application using below steps.
1. Right click the pom.xml file and Select "Maven clean"
2. Right click the pom.xml file and Select "Maven install"

Step 9

Create features by below configuration (filename: FuseFeatures.xml).

<?xml version="1.0" encoding="UTF-8"?>
<features name="MyFeaturesRepo">
<feature name="StudentEnrollment">
<bundle>file:C:/ranjiths/GD/j2r/ws/ws-jbossfuse/FuseExample/target/FuseExample-0.0.1-SNAPSHOT.jar
</bundle>
</feature>
</features>

Now our code implementation is over and time to Deploy into Fuse ESB.

DEPLOYMENT

Follow the below steps to deploy the application.
  1. Start the fuse by clicking ~jboss-fuse-6.2.0.redhat-133\bin\fuse.bat
JBossFuse:karaf@root>
  1. Install the feature
JBossFuse:karaf@root> features:addurl file:c:/ranjiths/GD/j2r/ws/ws-jbossfuse/FuseExample/FuseFeatures.xml
JBossFuse:karaf@root> features:install StudentEnrollment -> Enter
Note: StudentEnrollment - feature name in FuseFeatures.xml file
  1. Issue below command to check whether StudentEnrollment feature is started or not.
JBossFuse:karaf@root> list
You will get the output as below
[ 267] [Active     ] [            ] [Started] [   80] FuseExample (0.0.1.SNAPSHOT)

TESTING THE FEATURE

Follow the below steps to test our new StudentEnrollment feature.
  1. Open the RESTClient
  2. Copy the URL (http://127.0.0.1:1834/enrollmentService) from EnrollmentRouter.java
  3. Append /enrollStudent copied from EnrollmentDetails.java
  4. Final URL: http://127.0.0.1:1834/enrollmentService/enrollStudent
  5. Copy the content of EnrollStudent.xml into the Payload
  6. Select 'POST' Method
  7. Select Content-Type as application/xml
  8. Click 'Send'
  9. The xmls content will be copied with file name ID-XXX under ~jboss-fuse-6.2.0.redhat-133\enrollment\request
Please reply if you are getting any errors during execution. Also share your thoughts in the comment box.
Happy Knowledge Sharing!!!