Accueil > Equinox ServletBridge > OSGi Equinox in a Servlet Container [step5]

OSGi Equinox in a Servlet Container [step5]


In [step4], I have explained how host resources in the bridge WEB Application, and how use custom OSGi bundles (sample.http, sample.http2) directly from the workspace (no need to create and deploy JAR in the /plugins folder) with patch 323707.

In this article [step5] and next article [step6], I will explain how we can enjoy OSGi benefits for an another feature (different from HTTP services to register/unregister servlet) in OSGi Equinox in a Servlet Container. The bridge WEB Application can become Electronic Document Management WEB application which is composed with list of Documentary Collection. Each Documentary Collection is an OSGi bundle that we can start/stop with OSGi console to register/unregister it from the list of Documentary Collection. Here a scheme which explains this idea :

This scheme show you 3 sides :

Download

You can download servletbridge_step5.zip which contains following explained projects :

OSGi bundle – sample.collections.api

Here we create a bundle sample.collections.api which defines the Documentary Collections API (ICollection, CollectionsRegistry…) :

Why create a bundle instead of setting the Java sources in the bridge WEB Application? The answer is that API must be share between OSGi bundles sample.collection* from the workspace and the bridge WEB Application.

Create Bundle sample.collections.api with NONE Activator (unselect generate an activator, a Java class that controls the plug-in’s life cycle option).

ICollection – Java

In this bundle create sample.collections.api.ICollection interface like this :

package sample.collections.api;

public interface ICollection {

	String getId();

	String getLabel();
	
}

DefaultCollection- Java

Create a default implementation of sample.collections.api.ICollection interface with sample.collections.api.DefaultCollection class like this :

package sample.collections.api;

public class DefaultCollection implements ICollection {

	private String id;
	
	private String label;
	
	public DefaultCollection(String id, String label) {
		this.id = id;
		this.label = label;
	}
	public String getId() {
		return id;
	}
	
	public String getLabel() {
		return label;
	}
}

CollectionsRegistry – Java

Create sample.collections.api.CollectionsRegistry class which is used to register/unregister ICollection like this :

package sample.collections.api;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class CollectionsRegistry {

	private static CollectionsRegistry INSTANCE = new CollectionsRegistry();
	private List<ICollection> collections = new ArrayList<ICollection>();

	public CollectionsRegistry() {
	}

	public static CollectionsRegistry getRegistry() {
		return INSTANCE;
	}

	public void registerCollection(ICollection collection) {
		synchronized (collections) {
			collections.add(collection);
		}
		System.out.println("Register collection ID=" + collection.getId()
				+ ", label=" + collection.getLabel());
	}

	public void unregisterCollection(ICollection collection) {
		synchronized (collections) {
			collections.remove(collection);
		}
		System.out.println("Un-Register collection ID=" + collection.getId()
				+ ", label=" + collection.getLabel());
	}

	public Collection<ICollection> getCollections() {
		return Collections.unmodifiableCollection(collections);
	}

}

You can notice some System.out to observe in the console the registration/unregistration of some ICollection.

bridge – CollectionsServlet

The CollectionsServlet servlet is used to display ICollection registered in the CollectionsRegistry. It is call with the http://localhost:8080/bridge/collections URL :

This servlet is declared in the web.xml of the bridge WEB Application (different form /helloworld servlet of the sample.http bundle). This servlet doens’t know the OSGi context BundleContext.

CollectionsServlet – Java

Create in the bridge project, sample.collections.servlet.CollectionsServlet class like this :

package sample.collections.servlet;

import java.io.IOException;
import java.util.Collection;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sample.collections.api.CollectionsRegistry;
import sample.collections.api.ICollection;

public class CollectionsServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.getWriter()
				.write("<html><title>Documentary Collections</title><body><fieldset><legend>Documentary Collections</legend>");
		resp.getWriter()
				.write("<table border=\"1\"><thead><tr><th>Id</th><th>Label</th></tr></thead><tbody>");

		Collection<ICollection> collections = CollectionsRegistry.getRegistry()
				.getCollections();
		for (ICollection collection : collections) {
			resp.getWriter().write("<tr>");
			
			resp.getWriter().write("<td>");
			resp.getWriter().write(collection.getId());
			resp.getWriter().write("</td>");
			
			resp.getWriter().write("<td>");
			resp.getWriter().write(collection.getLabel());
			resp.getWriter().write("</td>");
			
			resp.getWriter().write("</tr>");
		}

		resp.getWriter().write("</tbody></fieldset></body></html>");

	}
}

At this step, there is compilation problem with sample.collections.api interface/classes.

Dependencies

To resolve compilation problem, bridge project must depends on sample.collections.api. The classic Project References doesn’t work in Dynamic WEB Project (it works for compilation but not for runtime). With WTP you must manage dependency with :

With this kind of dependencies, a JAR sample.collections.api.jar will be generated by WTP in the bridge/WEB-INF/lib when server start.

Java EE Modules Dependencies- Galileo

If you are using Galileo, open bridge Project Properties and go at Java EE Modules Dependencies node. Select sample.collections.api line :

Click on OK button.

If you start the server and you go at YOU_WORKSPACE/.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\bridge\WEB-INF\lib, you will see sample.collections.api.jar.

Deployment Assemblies – Helios

If you are using Galileo, open bridge Project Properties and go at Deployment Assemblies node :

Click on Add… button, and select Project node :

Select sample.collections.api node :

Click on Finish button :

Click on OK button. If you start the server and you go at YOU_WORKSPACE/.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\bridge\WEB-INF\lib, you will see sample.collections.api.jar.

CollectionsServlet – web.xml

Declare CollectionsServlet in the /bridge/WebContent/WEB-INF/web.xml like this :

<servlet>
  <servlet-name>CollectionsServlet</servlet-name>
  <servlet-class>sample.collections.servlet.CollectionsServlet</servlet-class>
</servlet>

Decalre the servlet mapping like this :

<servlet-mapping>
  <servlet-name>CollectionsServlet</servlet-name>
  <url-pattern>/collections</url-pattern>
</servlet-mapping>

Test

Go at http://localhost:8080/bridge/collections. You will see this page with none collections :

OSGi bundle – sample.collection1

Here we create a bundle sample.collection1 with an Activator which :

Create Bundle sample.collection1 with sample.collection1.internal.Activator. Modify Activator class like this :

package sample.collection1.internal;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

import sample.collections.api.CollectionsRegistry;
import sample.collections.api.DefaultCollection;
import sample.collections.api.ICollection;

public class Activator implements BundleActivator {

	private static BundleContext context;

	private ICollection collection = null;

	static BundleContext getContext() {
		return context;
	}

	public void start(BundleContext bundleContext) throws Exception {
		Activator.context = bundleContext;

		collection = new DefaultCollection("1", "Collection 1");
		CollectionsRegistry.getRegistry().registerCollection(collection);

	}

	public void stop(BundleContext bundleContext) throws Exception {
		Activator.context = null;
		CollectionsRegistry.getRegistry().unregisterCollection(collection);
		collection = null;
	}

}

There is compilation problem, because there are no dependency to sample.collections.api .

Modify sample.collections.api

With OSGi bundle, dependency is not managed with classic Project References. Import/Export packages must be used. In our case :

  • sample.collections.api must export sample.collections.api packages.
  • sample.collection1 must import sample.collections.api packages.

Export package

In sample.collections.api bundle, export packages sample.collections.api. To do that, open the META-INF/MANIFEST.MF and go at the Runtime tab :

Click on Add… button of the list Exported packages list. The Package Selection dialog opens :

Select sample.collections.api package and click on OK button :

Save the editor and go to the MANIFEST.MF tab. The MANIFEST.MF has changed by adding Export-Package: sample.collections.api :

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Sample Collections API
Bundle-SymbolicName: sample.collections.api
Bundle-Version: 1.0.0.qualifier
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Export-Package: sample.collections.api

Import package

In the sample.collection1 bundle, Import package sample.collections.api.

Here the sample.collection1/META-INF/MANIFEST.MF content :

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Sample Collection1
Bundle-SymbolicName: sample.collection1
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: sample.collection1.internal.Activator
Import-Package: org.osgi.framework;version="1.3.0",
 sample.collections.api
Bundle-RequiredExecutionEnvironment: J2SE-1.5

Test

At this step we can try to start the sample.collection1 to register it to the Collectionsregistry. To do that modify the config.ini to add sample.collection1 bundle :

,${workspace_loc}/sample.collection1@start

Restart your server (/sp_redeploy + restart server) and type in the console View

ss

The OSGi console display the Short Status of the bundles installed :

...
7 INSTALLED sample.collection1_1.0.0.qualifier

You notice that sample.collection1 has INSTALLED state (there is a problem). Force the start with OSGi console and you will see following error :

osgi> start 7
org.osgi.framework.BundleException: The bundle could not be resolved. Reason: Missing Constraint: Import-Package: sample.collections.api; version="0.0.0"
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:305)
...

The sample.collections.api is in the WEB-INF/lib and not in the /plugins folder. OSGi Equinox doesn’t know this bundle. We will see in [step6], how fix this problem.

Conclusion

This sample is interesting because :

  • it show an another sample of OSGi benefits without HTTP services registry.
  • WEB Applcation and OSGi conteneur must share CollectionsRegistry instance. I will explain how manage that in [step6]
  • WEB Application is very modular because Collection can be started/stoped without stopping server (interesting in development/production mode).

In this article we initialized the Electronic Document Management WEB Application, except that sample.collection1 cannot be used, because sample.collections.api is missing in the OSGi Equinox container. We will see in [step6], how fix this problem.

Catégories :Equinox ServletBridge
  1. Aucun commentaire pour l’instant.
  1. septembre 9, 2010 à 10:58
  2. septembre 10, 2010 à 3:37

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :