Thursday 6 March 2014

FUSE OSGI with CXF based web services

FUSE OSGI:

Overview:
JBoss Fuse is an open source integration platform based on Apache ServiceMix that supports JBI and OSGi for use in wide ranges of enterprise application. It is robust SOA infrastructure that provides a standardized methodology, server, and tools to integrate components in mission-critical applications.
Fuse ESB has the following layered architecture:
·         Technology layer—includes technologies such as JBI, JAX-WS, JAX-RS, JMS, Spring, and JEE
·         Fuse ESB kernel — it is a wrapper layer around the OSGi container implementation, which provides support for deploying the OSGi container as a runtime server.
·         OSGi framework —it implements OSGi functionality, including managing dependencies and bundle lifecycles.
The following diagram shows architecture of fuse ESB.

·        Console: It manages services, installs and manages applications and libraries, and interacts with the Fuse ESB kernel runtime.
·        Logging: Provides a powerful logging system to display view and change log levels.
·        Deployer: It supports hot deployment of OSGI bundles, upon updating or deletion changes are automatically reflected.
·        Spring DM: Simplifies building spring application that runs in an OSGI.


Installation:
Fuse can be easily installed into windows systems.
 Search for Fuse ESB Enterprise, download windows installer & install it in the same way as other applications are installed into windows.
I suppose the installation is done at “C:\FuseESBEnterprise-7.0.1”, where you will see all the fuse ESB related installation folder and files.

FUSE ESB Configuration:
All the OSGI configuration files are located at InstallDir/etc directory. A configuration is a list of name-value pairs read from a .cfg file in fuse.
org.apache.karaf.features.cfg: This contains configuration of list of features available in fuse.  While running Fuse, it will look for this configuration file to load all the features.  If you want your custom feature to be added in fuse, then you need to add a custom feature file in the featuresRepositories section as below.
featuresRepositories=\
                 mvn:org.apache.karaf.assemblies.features/standard/2.2.5.fuse-70-084/xml/features,\

In above example, I have added custom-features.xml feature file to a feature repository section. This feature file will contain all of my project specific bundles & other features which are not natively available in fuse such as hibernate features, spring features, Junit features, cache features which are required in your application to deploy a bundle.
The features are described in a features XML descriptor. 
Here is an example of custom-features.xml file:


Here, you can see the feature file that contains the feature named “hibernate”, then <bundle></bundle> tag which is used to include the specific feature file. For ex- if I need a hibernate jar to be included in my bundle, I am giving a reference name.
It is important here to understand that some features are provided through fuse itself. The mvn:org.hibernate/com.springsource.org.hibernate/3.3.2.GA is provided by fuse itself. However all the features that are needed in your application, might not be provided from fuse. In that case you need to install it through your system directory itself.
<bundle>wrap:file:///C:/FuseESBEnterprise-7.0.1/lib/ext/Juint/junit/4.7/junit-4.7.jar</bundle> is an example of installing a bundle through the file system.
To install a bundle through mvn repository, we use a command: mvn:groupId/ArtificatId/Version. The last 2 bundles common & group are an example of installing application specific bundle through maven repository.

Enable Debugging:
You can enable debugging in a fuse by editing property /bin/karaf.bat or in fuseesb.bat
KARAF_DEBUG=true
set DEFAULT_JAVA_DEBUG_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
Here 5005 is a debug port allocated for fuse.

Configuring HttpPort:
Open /etc/system.properties , modify the port number
org.osgi.service.http.port=8181

Starting fuse:
You can start fuse by running a fuseesb.bat file located at /bin directory. By default fuse start deploying native bundles first which are around 218. After that an application specific custom bundles will be deployed. All the deployed bundled are seen at \data\cache directory. You can monitor the progress of deployment through a log file which is created at \data\log directory. The log file greatly helps us to roll out exiting deployment errors & informations.

Modifying an Existing Maven web service Project to work with fuse:
An existing modular maven project can be easily deployed at fuse with some minor changes at POM file.
ð  Modify a POM to generate bundle:  To configure a maven to generate bundle we need basically 2 things :
o    Change the POM's package type to bundle: <packaging>bundle</packaging>
o   Add the Maven bundle plug-in:


All dependent packages that are required for an application bundle need to be explicitly mentioned at <Import-Package> section. For example for a web service project that uses Apache cxf component need to include the following dependent packages.





   
Apart from this, if your application is based on Hibernate & Spring, you need to include those packages as well inside import section. Further-more all our application specific components are required to be included. These all imports are mandatory for maven-bundle-plugin to generate Manifest.Mf file which can be seen inside the bundle at:
                             data\cache\bundleName\version0.0\bundle.jar\META-INF\ location
While application is exposed through a client, the fuse will use Manifest.Mf file to read and locate related information about this specific bundle.
In <Export-Package> section, we provide those package which are required outside of this bundle & useful to other bundle. The exported package of bundle can be imported by other bundles if they are dependent on those packages.
Here is a sample POM:





Few useful FUSE ESB commands:
Installing a new bundle:
The following commands install a new bundle through a file and maven repository respectively.
·         osgi:install -s file:D:/fuse-test/test/common/target/test.jar
·         osgi:install mvn:com.test.plan/plan/0.0.1-plan
·         list: Provides list of all installed bundles in the system
·          
·         osgi:start : Starts a specific bundle . Eg: osgi:start 130  will start bundle number 130
·         osgi:stop : Stops a specific bundle
·         osgi:uninstall: Uninstalls a bundle with provided bundle id. Eg: osgi:uninstall 130
·         osgi:stop: Stops a bundle Eg: osgi:stop 130
·         osgi:bundle-level: Gets or sets the start level of a given bundle.
·         osgi:headers: Displays OSGi headers of a specified bundle.
·         osgi:refresh: Refreshes the bundle.
·         osgi:resolve: Resolves the bundle.
·         osgi:restart: Restarts a bundle.
·         osgi:shutdown: Shuts down the OSGI framework.
·         osgi:update: Updates the bundle.
·         commandName –help: Displays the online help for command X


When you hit a command list at console, it will list all the bundles with their bundle id & their states – Active, started, Stopped etc.

Changing default root URL:
By default CXF based web services in Fuse OSGI publishes an endpoint URL with /cxf extension. For example if your project is hosted as 8181 port, web service will be invoked through http://localhost:8181/cxf/YourWebservice?wsdl.
This feature is often messy, because I do not want endpoint URL root name to be cxf. Instead I would be happy if I can update the name  related an application. In sort I would like a name such as http://localhost:8181/yourApplication/YourWebservice?wsdl.
To do this, fuse does not provide a default mechanism. Instead we need to add one file named
org.apache.cxf.osgi.cfg, place it in /etc directory and add the following line to the file.
org.apache.cxf.servlet.context=/yourApplication

This will override the default endpoint root URL name provided by the CXF component.

       
Troubleshooting:
If two application server are using same port Example – Jboss & Fuse, you will get the following messy message at the fuse console:
Caused by: java.io.IOException: Cannot bind to URL [rmi://localhost:1099/karaf-root]

This means existing port 1099 is already in use by some other application.

In /etc  directory check the configuration file org.apache.karaf.management.cfg and update the following property.

rmiRegistryPort = 1100

Update the same configuration to system.properties file too.