January 22, 2009

Configuring Apache Felix to host web applications

I have been doing lot of work on OSGi technologies lately. Recently we have seen many application server move from their core server technologies to OSGi based ones. In this article we will see how to configure Apache Felix to host simple web applications built using JSP and servlet technology.

We have less stuff to do. Thanks to the community, all you need to do is download the necessary bundles, make your WARs an OSGi bundle and finally load all the bundles on an OSGi runtime.

OPS4J community provides us the necessary bundles that help us host WAR files. We will use OPS4J three projects: Pax Web, Pax Web Extender and Pax logging.

Pax web is a OSGi R4 HTTP Service implementation using Jetty 6.

Pax Web Extender is a project that extends and adds more functionality to Pax web. The extender project has three modules: Pax Web Extender – War, Pax Web Extender – Whiteboard and Pax URL. We will be using the Pax Web Extender – War bundle. The bundle that makes possible to deploy WAR files into OSGi runtime.

And finally, Pax logging provides an OSGi logging service and API. It is built on top of log4j and supports Jakarta Commons Logging API, Log4J Logger API, JDK Logging, Avalon Logger API, Knopflerfish Log and Tomcat Juli in both your own code and in third party libraries.

You can download these from OPS4J site.

Build your web application on any IDE or compile it into a war using Ant. But before deployment we need to ensure that the archive is a valid bundle. To make the web application a bundle we need to have the following manifest headers in META-INF/MANIFEST.MF.

Bundle-ManifestVersion: 2 -- This header defines that the bundle follows R4 specification.
Bundle-SymbolicName -- This header specifies a unique, non-localizable name for the bundle.
Bundle-ClassPath –- This header specifies list of all JAR and resources in your bundle. Each entry is separated by comma and the root directory is represented by period. Example: Bundle-ClassPath: .,WEB-INF/classes,lib/commons-logging.jar,lib/spring.jar
Import-Package -- This header defines the list of packages that your application depends on. All necessary J2EE packages would come here.

Additionally, you can have some optional headers like
Webapp-Context -- The header defines the context path. Please note that this is not a standard OSGi header.

You may also include other standard OSGi headers for adding information to the bundle. Once you have the WAR file with modified manifest information we are ready to deploy our application. Deployment is simple the installation of the bundle.

You can install the bundle using the install command from the Felix shell or modify the conf/config.properties. Once installed, check if the bundle’s state is active and then access your web application using your browser.

Caution: Please note that, if you have created your WAR using Netbeans you will have sun-web.xml. More than one configuration file causes resource registration failure in Pax Web Extender. You will have to remove this file.

For now we have only used one of the modules from Pax Web Extender. You may try other modules as they also provide interesting functionalities for a developer.

1 comment :

Raul said...

Hello I am having an error while deploying my web app in felix container. The pax bundles that I am using are:
pax-web-service-0.6.0.jar
pax-web-jsp-0.7.1.jar
pax-web-extender-war-0.7.1.jar
pax-logging-service-1.5.0.jar
pax-logging-api-1.5.0.jar
Browser displays:
HTTP ERROR 403

Problem accessing /adminmodule/. Reason:

FORBIDDEN

Powered by Jetty://


Console Log:

/adminmodule/] DEBUG org.mortbay.jetty - REQUEST /adminmodule/ on org.mortbay.jetty.HttpConnection@1e94001
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.ops4j.pax.web.service.internal.model.ServerModel - Matching [/adminmodule/]...
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.ops4j.pax.web.service.internal.model.ServerModel - Path [/adminmodule/] matched to {pattern=/adminmodule/.*,model=ResourceModel{id=org.ops4j.pax.web.service.internal.model.ResourceModel-2,name=,urlPatterns=[/],alias=/,servlet=ResourceServlet{context=/adminmodule,alias=/,name=},initParams={},context=ContextModel{id=org.ops4j.pax.web.service.internal.model.ContextModel-1,name=adminmodule,httpContext=org.ops4j.pax.web.extender.war.internal.WebAppWebContainerContext@11710be,contextParams={webapp.context=adminmodule}}}}
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.ops4j.pax.web.service.internal.HttpServiceContext - Handling request for [/adminmodule/] using http context [org.ops4j.pax.web.extender.war.internal.WebAppWebContainerContext@11710be]
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.mortbay.jetty - sessionManager=org.mortbay.jetty.servlet.HashSessionManager@19c6163
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.mortbay.jetty - session=null
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.mortbay.jetty - servlet=
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.mortbay.jetty - chain=org.ops4j.pax.web.service.internal.model.FilterModel-3->
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.mortbay.jetty - servlet holder=
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.mortbay.jetty - call filter org.ops4j.pax.web.service.internal.model.FilterModel-3
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.ops4j.pax.web.service.internal.WelcomeFilesFilter - Apply welcome files filter...
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.ops4j.pax.web.service.internal.WelcomeFilesFilter - Servlet path: /
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.ops4j.pax.web.service.internal.WelcomeFilesFilter - Path info: null
[5884890@qtp-16567002-0 - /adminmodule/] INFO org.ops4j.pax.web.service.internal.HttpServiceContext - getting resource: [/adminmodule.jsp]
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.ops4j.pax.web.extender.war.internal.WebAppWebContainerContext - Searching bundle [com.cisco.zaloni.gwt.admin [1]] for resource [/adminmodule.jsp], normalized to [adminmodule.jsp]
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.ops4j.pax.web.extender.war.internal.WebAppWebContainerContext - Resource not found
[5884890@qtp-16567002-0 - /adminmodule/] INFO org.ops4j.pax.web.service.internal.HttpServiceContext - found resource: null
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.mortbay.jetty - call servlet
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.ops4j.pax.web.extender.war.internal.WebAppWebContainerContext - Searching bundle [com.cisco.zaloni.gwt.admin [1]] for resource [/], normalized to [/]
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.ops4j.pax.web.extender.war.internal.WebAppWebContainerContext - Resource found as url [bundle://1.0:1/]
[5884890@qtp-16567002-0 - /adminmodule/] DEBUG org.mortbay.jetty - RESPONSE /adminmodule/ 403

I removed the
pax-web-jetty-bundle-0.7.1.jar
pax-web-extender-whiteboard-0.7.1.jar

as I have not seen any use of these bundles.

Any idea please.