OSGi Equinox in a Servlet Container [step4]
In [step3], I have explained why it’s important to define Target Platform with OSGi Equinox in a Servlet Container to compile your custom bundle (sample.http, sample.http2…) with the bundles JARs coming from bridge/WebContent/WEB-INF/eclipse/plugins folder (and not coming from the Eclipse IDE).
In [step2], we have seen 2 problems :
- It’s impossible to host some resources (HTML, Javascript, Servlet…) in the bridge WEB Application (when /* URL pattern is used). I will explain how fix this problem by using BridgeFilter coming from patch 323707.
- It’s impossible to use directly the OSGi bundle coming from the workspace. You must create a JAR and copy/paste to the /plugins folder. I will explain how fix this problem by using ${workspace_loc} wildcard (to declare bundles in config.ini) coming from patch 323707.
The current distribution of OSGi Equinox in a Servlet Container doesn’t manage this 2 features, so I have decided to improve it with patch 323707. In this article I will explain how use this patch to manage the 2 problems explained below.
Download
You can download servletbridge_step4.zip which contains following explained projects :
- bridge which contains :
- the JAR patched lib/org.eclipse.equinox.servletbridge_1.2.0.201008301518.jar and plugins/org.eclipse.equinox.http.servlet_1.1.0.201008310825.jar.
- the web.xml wich declare BridgeFilter instead of BridgeServlet.
- the resources WEB-INF/WebContent/index.htm, WEB-INF/WebContent/index.jsp.
- JAR of sample.http and sample.http2 deleted.
- bridge.target Target Platform modified (at hand by editing with NodPad) to remove the sample.http and sample.http2 and the version of the org.eclipse.equinox.http.servlet with 1.1.0.201008310825 version.
- sample.http2 which define /bin2 as output folder (instead of /bin folder) explained in bundleClassPathEntries section.
- the same projects than [step2].
BridgeFilter – Add resource in bridge webapp
To use OSGi Equinox in a Servlet Container, the BrideServlet must be declared as an servlet. It works well except it causes the problem that it’s impossible to host some resources (JSP, HTML, Servlet…) in the bridge WEB Application, if /* URL servlet-mapping pattern is used. To resolve this problem, patch 323707 provides the capability to declare the « BrideServlet » as a Filter with BridgeFilter .
In this section we will see the problem with BridgeServlet, how BridgeFilter resolve this problem and I will explain why Filter using resolve the problem.
The problem with BridgeServlet
Add index.htm
Create the WEB-INF/WebContent/index.html file with this content :
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>OSGi Equinox in a Servlet Container - Home Page</title> </head> <body> <div>OSGi Equinox in a Servlet Container - Home Page</div> </body> </html>
When you go at http://localhost:8080/bridge/index.htm, you will have a 404 error :
This error message show you that BridgeServlet send a 404 error because it tries to search a resources registered ONLY with OSGi services (like /helloworld).
The fix problem – BridgetFilter
To resolve the problem of hosting some resources in the bridge WEB Application, you must use patch 323707 :
- Download the zip NewServletBridge_*.zip from the patch 323707.
- Replace the servletbridge.jar with the JAR org.eclipse.equinox.servletbridge_1.2.0.201008301518.jar.
- Replace org.eclipse.equinox.http.servlet_1.0.0.200704022148.jar with the JAR org.eclipse.equinox.http.servlet_1.1.0.201008310825.jar.
You workspace looks like this :
Now you can declare BrigeServlet with BridgeFilter (with Filter). To do that modify web.xml like this :
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <filter id="bridge"> <filter-name>equinoxbridgefilter</filter-name> <filter-class>org.eclipse.equinox.servletbridge.BridgeFilter</filter-class> <init-param> <param-name>commandline</param-name> <param-value>-console</param-value> </init-param> <init-param> <param-name>enableFrameworkControls</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>equinoxbridgefilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- This is required if your application bundles expose JSPs. --> <filter-mapping> <filter-name>equinoxbridgefilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> </web-app>
You will notice that Servlet 2.4 is declared here :
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> ... </web-app>
Because Filter is available with <=Servlet 2.3. You could declare too Servlet 2.3 like this :
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> ... </web-app>
Retry
Restart your server and go at http://localhost:8080/bridge/index.htm, you will see the /index.htm content :
index.jsp
The bridge/WEB-INF/WebContent folder of the patch 323707 provides the index.jsp which display list of /sp_* commands frameworks. If you copy/paste it in your bridge/WEB-INF/WebContent and you go at http://localhost:8080/bridge/index.jsp, you will see the /sp_* whole commands with HTML links :
Why Filter using resolve the problem?
When BridgeServlet doesn’t find an OSGi services with the path required (ex : /index.jsp), the servlet send a 404 error, with this code
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "BridgeServlet: " + req.getRequestURI());
When BridgeFilter doesn’t find an OSGi services with the path required (ex : /index.jsp), the filter gives the hand of the HTTP server by calling this code :
chain.doFilter(req, resp);
${workspace_loc} : Use bundles form the workspace
When you develop custom bundles (ex : sample.http, sample.http2….), you must create and deploy JARs as soon as you change your Java code of your bundle. In development mode, this action can be really annoying. The patch 323707 gives you the capability to use directly your bundles from your workspace (no need to create and deploy JARs).
This feature can works too with BridgeServlet. If you wish manage that, the only org.eclipse.equinox.servletbridge_1.2.0.201008301518.jar is required.
${workspace_loc}
patch 323707 gives you the capability to declare your bundles in the osgi.bundles property of the config.ini with :
reference\:file\:YOUR_PATH_FOLDER/YOUR_BUNDLE
where :
- YOUR_PATH_FOLDER is the path folder of your bundles (ex : your workspace path location).
- YOUR_BUNDLE is your bundle name (ex : sample.http).
In my case my workspace path location is D://_Projets/Personal/workspace-servletbridge-wordpress/step4, so I can write :
reference\:file\:/D\:/_Projets/Personal/workspace-servletbridge-wordpress/step4/sample.http
But path hard-declared is not very usefull when several developers works in the same project. So it’s possible (and it’s adviced) to use ${workspace_loc} wilcard like this :
${workspace_loc}/YOUR_BUNDLE
Here the osgi.bundles property of the config.ini used in this article :
osgi.bundles=org.eclipse.equinox.common@2:start, org.eclipse.update.configurator@start, org.eclipse.equinox.http.servletbridge@start, org.eclipse.equinox.http.registry@start,${workspace_loc}/sample.http@start,${workspace_loc}/sample.http2@start,org.apache.felix.webconsole@start
The value of the ${workspace_loc} can be :
- computed, if WEB Application is deployed inside the Eclipse Workspace.
- or setted, if WEB Application is deployed outside the Eclipse Workspace.
WEB Application (deployed) INSIDE Workspace
When WEB Application is deployed inside the .metadata folder of the Workspace, ${workspace_loc} can be computed. This case comes from for instance with WTP Module (our case). For more information, please read WTP Deployment [step3].
To use sample.http and sample.http2 from the bundles workspace :
- remove the bridge/WebContent/WEB-INF/eclipse/plugins/sample.http_1.0.0.jar and bridge/WebContent/WEB-INF/eclipse/plugins/sample.http2_1.0.0.jar
- modify the bridge/WebContent/WEB-INF/eclipse/configuration/config.ini to use ${workspace_loc} like this :
osgi.bundles=org.eclipse.equinox.common@2:start, org.eclipse.update.configurator@start, org.eclipse.equinox.http.servletbridge@start, org.eclipse.equinox.http.registry@start,${workspace_loc}/sample.http@start,${workspace_loc}/sample.http2@start,org.apache.felix.webconsole@start
- start your server and go at http://localhost:8080/bridge/sp_rdeploy
Check your config.ini replaced your old config.ini with your real Eclipse Workspace path. In my case I have :
osgi.bundles=org.eclipse.equinox.common@2\:start,org.eclipse.update.configurator@start,org.eclipse.equinox.http.servletbridge@start,org.eclipse.equinox.http.registry@start,reference\:file\:/D\:/_Projets/Personal/workspace-servletbridge-wordpress/step4/sample.http@start,reference\:file\:/D\:/_Projets/Personal/workspace-servletbridge-wordpress/step4/sample.http2@start,org.apache.felix.webconsole@start
Restart your server and type in the console View
ss
The OSGi console display the Short Status of the bundles installed :
...
15 ACTIVE sample.http_1.0.0
16 ACTIVE sample.http2_1.0.0
- sample.http is ACTIVE : the http://localhost:8080/bridge/helloworld URL is available.
- sample.http2 is ACTIVE : the http://localhost:8080/bridge/helloworld2 URL is available.
WEB Application (deployed) OUTSIDE Workspace
When WEB Application is deployed outside the .metadata folder of the Workspace, ${workspace_loc} must be setted. This case comes from for instance with WTP External Module. To set the workspace_loc value path, you can do it in the web.xml with init-param of the BridgeFilter (or BridgeServlet) like this :
<init-param> <param-name>workspace_loc</param-name> <param-value>D://_Projets/Personal/workspace-servletbridge-wordpress/step4</param-value> </init-param>
bundleClassPathEntries
At this step, sample.http2 compile Java classes to the /bin folder. To check that Open the Navigator View with Window/Show View/Other… and General/Navigator :
Sometimes you wish customize this output folder. To do that Go at Properties Project of the sample.http2 and click on Java Build Path node. Change « Default output folder » with sample.http2/bin2 :
Click OK and go to the Navigator View to check classes are stored in /bin2 folder :
Restart your server and type in the console View
ss
The OSGi console display the Short Status of the bundles installed :
...
15 ACTIVE sample.http_1.0.0
16 RESOLVED sample.http2_1.0.0
You will notice that sample.http is ACTIVE (it works) but sample.http2 is RESOLVED (problem).
If you try to force the start of the sample.http2 (in my case with start 16), you will see in the console :
osgi> start 16
org.osgi.framework.BundleException: The activator sample.http2.Activator for bundle sample.http2 is invalid
...
Caused by: java.lang.ClassNotFoundException: sample.http2.Activator
at java.net.URLClassLoader$1.run(Unknown Source)
The error show you that OSGi Equinox container cannot find classes of the sample.http2. To resolve that, you must configure BridgeFilter (or BridgeServlet) to set the classes output folder. In our case, we have :
- /bin for the sample.http.
- /bin2 for the sample.http2.
To configure that, you can do it in the web.xml with bundleClassPathEntries as init-param of the BridgeFilter (or BridgeServlet) like this :
<init-param> <param-name>bundleClassPathEntries</param-name> <param-value>bin,bin2</param-value> </init-param>
Restart your server and type in the console View
ss
The OSGi console display the Short Status of the bundles installed :
...
15 ACTIVE sample.http_1.0.0
16 ACTIVE sample.http2_1.0.0
The sample.http and sample.http2 must be ACTIVE. Here the full web.xml used in this article :
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <filter id="bridge"> <filter-name>equinoxbridgefilter</filter-name> <filter-class>org.eclipse.equinox.servletbridge.BridgeFilter</filter-class> <init-param> <param-name>commandline</param-name> <param-value>-console</param-value> </init-param> <init-param> <param-name>enableFrameworkControls</param-name> <param-value>true</param-value> </init-param> <!-- <init-param> <param-name>workspace_loc</param-name> <param-value>D://_Projets/Personal/workspace-servletbridge-wordpress/step4</param-value> </init-param> --> <init-param> <param-name>bundleClassPathEntries</param-name> <param-value>bin,bin2</param-value> </init-param> </filter> <filter-mapping> <filter-name>equinoxbridgefilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- This is required if your application bundles expose JSPs. --> <filter-mapping> <filter-name>equinoxbridgefilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> </web-app>
How it works?
To understand how it works, go at the Tomcat work folder where /eclipse folder is deployed (For more information, please read WTP Deployment [step3]). You will notice :
- work/Catalina/localhost/bridge/eclipse/configuration/config.ini : ${workspace_loc} is replaced with your Workspace path location. In my case I have :
osgi.bundles=...reference\:file\:/D\:/_Projets/Personal/workspace-servletbridge-wordpress/step4/sample.http@start,reference\:file\:/D\:/_Projets/Personal/workspace-servletbridge-wordpress/step4/sample.http2@start
work/Catalina/localhost/bridge/eclipse/dev.properties exists, which is a file generated when HTTP server start. It contains for each bundles declared with reference\:file the list of output folder to use :
sample.http2=bin,bin2 sample.http=bin,bin2
OSGi Equinox container (org.eclipse.core.runtime.adaptor.EclipseStarter()) is called with osgi.dev parameter by setting the path of the dev.properties file. For more informations about the Equinox OSGi container configuration, please read The Eclipse runtime options.
Conclusion
In this article we have seen that patch 323707 can be helpfull to :
- host some resources (HTML, Javascript, Servlet…) in the bridge WEB Application.
- use directly the OSGi bundle coming from the workspace with create and deploy a JAR in the /plugins folder.
In [step5], I will explain how we could use Equinox in Servlet Container to enjoy OSGi for an another features (different from HTTP services). We will transform bridge WEB Application to have (a simple) Electronic Document Management WEB application which manage Documentary Collection. Documentary Collection will be managed with an OSGi bundle that we will able to start/stop (with OSGi console) to register/unregister it to the Documentary Collections.
Hi, I come across your post when researhing on the possibilities of using the equinox http service registry inside an web application bundle ( wab ) on the eclipse geminiweb osgi web container. This looks great, will try to get this working inside WAB.
Hi Heng,
I’m happy that my post seems please you. Hope you will not have problem with WAB.
Regards Angelo
Hi, I would like to update that using your patches, I have adapted the equinox servlet bridge to work inside a web application archive running on the gemini web container. The modified source is here: http://kenai.com/projects/hengsin/sources/development/show in three bundle – org.adempiere.eclipse.equinox.http.servlet, org.adempiere.eclipse.equinox.http.servletbridge and org.adempiere.eclipse.equinox.servletbridge. Example usage is in the org.adempiere.webstore and org.adempiere.webstore.servlet bundle.
Hi Heng,
Thank’s for your share. Perhaps it should be cool to provide your patch to Eclipse?
Regards Angelo
Do you have an example for how one can use Spring Dispatcher Servlet with the Bridge Filter ?
No sorry.
I’m really pleased with this post, it was for a great help to me. I couldn’t thank you enough for your great efforts and all that i learned here with you.
Thank you.
Best Rgrds,
Ahmed EL AMINE
Hi Ahmed ,
Thank a lot for your post. I’m happy that my articles can be help you.
Regards Angelo
Hi *,
just for convenience I want to edit my sources and see the changes immediately in the browser. This only works when Tomcat runs in DEBUG MODE in Eclipse.
Happy coding
Alex
Hi,
i am getting ClassNotFound Exception for the Activator eventhough I can see created dev.properties includes my plugins /bin dir. I copied the bin directory directly to bundle root dir and it works without a problem what may be causing this so my runtime does not see the /bin as source folder.
Regards
Eren