The "One Laptop Per Child" project has a great device ready to ship, but there's no Java on there. Let's think about working together to put Java on OLPC!
The author of this article is co-author of the book "Struts Best Practices" published in German (2004) and French (Feb 2005). He has been working with Java n-tier web since 1998, including SilverStream appserver, before the advent of OS and J2EE.
His company, Infonoia SA is editor of multi-platform, multi-repository software and solutions around document retrieval and publishing.
Infonoia also provides consulting services, mentoring and training (English, French, German) on Best Practices in the web technologies and frameworks they use, such as Struts, Eclipse and RSP. Wolfgang is also available for speaking engagements on RSP.
Wolfgang can be reached at wgehner at infonoia dot com.
About this Tutorial
This tutorial is split into two parts. The
first part
will
cover a sample web application all the way to creating the necessary
extension points for your own. The
second part
will pickup right where
Part 1
left off and guide you through mapping your servlet,
dependencies and then eventually running your new web application.
Introduction
Welcome to Part 2 of the OSGi Web Application tutorial. You should
have read
Part 1
by now and have everything setup
appropriatley to continue working on our sample web application. We are
going to dig right into extensions, servlets, resources and more. So
let's get started!
Extensions and Extension points
Now let's look at the wizardry that creates these URL servlet and
resource mappings behind the scenes from
Part 1
.
The magic is in the file
plugin.xml
included in each plug-in. It uses an Eclipse-specific mechanism
(invented even before Eclipse migrated to OSGi infrastructure) called
"Extensions" and "Extension points". Extensions
provide a way to specify possible interactions between plug-ins.
[Image 9: Extensions in the plug-in editor]
Extension points in Eclipse are what makes, for example menu items ,
show up on the menu bar (the
org.eclipse.ui.menus
extension
point, among others, for historical reasons, in this particular case).
The menu renderer obtains the "Extensions" from the
"Extension registry" and builds the menu from that
information.
Part of my vision for a "Eclipse/OSGi server-side UI framework is
to use the same mechanism to build menus, views, editors etc. the same
way for server-side applications. However, this demo app
"just" uses the extension points to make HTTP output from
different plug-ins accessible.
Note: Release 4 of the OSGi-standard provides a different mechanism
called "declarative services" to achieve what the
Eclipse-specific extensions do, and more. Eclipse 3.2 final is likely
to
support declarative services (since it's part of the OSGi-implentation
Eclipse uses); but plug-in Editor support may only be for a later date.
Mapping servlets
Go to the project
org.rsp.framework.struts
, open
plugin.xml
,
select the
plugin.xml
tab and inspect it. You will find
the
following:
[Image 10: PluginXmlServlet]
This is an Extension which provides the description for a servlet as
you
would normally find in your application's
WEB-INF/web.xml
.
The webapp has a
web.xml
, but it is outside of this
particular plug-in, and providing the mapping there would of course
defeat the purpose of "component" plug-ins. [Note: You will
find a web.xml also in
/WEB-INF/
of the
org.rsp.framework.struts
plug-in. However, it is only there to avoid errors during
precompilation
of JSPs, and otherwise defunct.] However, code in the webapp (in the
Equinox plug-in jars, actually) reads the information from the
Extensions, and registers the servlets described there in the
BridgeServlet
shown earlier.
The structure of servlet "extension points" is similar, but
not quite identical to what you would find in a
web.xml
.
replaces
and
is new. The OSGi standard specifies that each HTTP service (used by the
BridgeServlet
, under the hood) uses a different
ServletContext
*
unless the
HttpContext
is shared*. This could create
problems in case of MVC forwards, where usually certain information is
passed from the first servlet to the second via the request context.
That transport would be broken under Eclipse-OSGi if different or
"null" HttpContexts are used among the related servlets. The
trick is to give all servlets and resources the same "
httpcontext-name
".
The name of our choice is "cross-context" (alluding to the
Tomcat server.xml attribute as in
cross-context="true"
,
which does similar things but across web applications.).
Now we know how a servlet is mapped from the bundle to the container.
The same works for precompiled JSPs (more about precompiling below).
This is a combination of two extension points. The "
httpcontexts
"
extension point specifies which directories in a plug-in JAR actually
get exposed as a http resource. In our case, this is *everything*
recursively under the
/WebContent
directory in the
plug-in
JAR.
The "
resources
" extension point specifies under
what (sub)namespace this happens. Again, a "
httpcontext-name
"
is given to allow sharing of context across plug-ins.
Is this complicated? Well, we think that all three extension points
could be rolled into one that more closely resembles a classic
web.xml
,
with just a namespace and context-path (
/WebContent
)
added.
Someone just needs to do it, this is open source
Maybe, eventually, extension points get deprecated in favor of
OSGi-standard "declarative services". Or wrapped. Now Eclipse
uses a custom "extension point registry", for lookup . If a
reader of this article is interested in implementing web.xml-style
declarative services, please let me know.
Please do not forget that not everything that is seen in the Eclipse
IDE
plug-in project automatically goes into the plug-in JAR. The plug-in
jar
contents need to be specified on the "Build" tab of the
plug-in editor.
[Image 12: Build tab]
Now we understand how resources are mapped from the bundle to the
container, and what goes into a plug-in jar. One more important
conceptual thing: Dependencies. The good news: it is downhill from
there.
Dependencies
The OSGi specification recommends that a bundle is deployed as a
single
JAR. For the Eclipse IDE, most plug-ins (see the
C:\rsp\eclipse\plugins
folder) are now single-JAR plug-ins. However, some plug-ins are
"exploded" into the file system; however, single-JAR plug-ins
are more performant. Moving to single-JAR plug-ins mostly is what made
startup of the Eclipse Workbench faster in the latest releases.
Single-JAR plug-ins have just one "problem": they cannot
contain other JARs, while exploded plug-ins can. But there is a
solution.
More involved (=advanced) plug-ins will usually depend on the presence
of other libraries (JARs) in the runtime environment. For example, the
org.rsp.sample.usage.customtaglib
plug-in uses the displaytag libary, which is provided in a separate
JAR.
Could we just add that JAR inside the customtaglib plug-in? Yes, we
could. We would just have to declare the JAR on the bundle classpath.
Of
course we would have to repeat that for every bundle which has that
dependency. And we might end up with a maintenance nightmare.
The clean solution is to make that dependent JAR a separate Eclipse
plug-in, and declare it as a "Required Plug-in" for the
plug-in that depends on it. You can do that on the
"Dependencies" tab of
plugin.xml
of the plug-in
that requires the other. (Boy, take a deep breath, read the first part
of this paragraph again, and make sure you understand it before you go
on, please).
[Image 13: Dependencies for Customtaglib]
Creating "simple" plug-in JARs from existing JAR
archives
Creating a plug-in JAR from an existing JAR archive is a two-step
process: creating the plug-in project from the existing JAR archive,
and
"exporting" the plug-in as plug-in JAR archive.
You can create a plug-in from an existing JAR archive with the
"
File/New/Other
" Wizard "
Plug-in Development/Plug-in
from
existing JAR archives
".
[Image 14: JAR Plugin Wizard]
We call plug-ins created from existing JAR archives
"
Simplejar
" plug-ins, and maintain them in the
"Simplejar" Working Set. (Menu Window-Working Sets-Edit,
select Simplejars, press Edit, and check the newly added project).
By the way, just having code in a plug-in jar does not make that code
accessible to other plug-ins that declare the dependency to this
plug-in! You also need to make sure that the packages you wish to make
accessible are listed as "Exported Packages" on the
"Runtime" tab of the plug-in. In the Eclipse IDE, you can
access the "Runtime" tab by opening either
build.properties
,
/META-INF/MANIFEST.MF
or
plugin.xml
(if
available). The abovementioned wizard automatically creates entries in
the "Exported Packages" list, so for simple plug-ins created
from existing JAR archives this is less of an issue.
But you are almost bound to forget this when you create your own
plug-ins from scratch, or add new code packages to an existing plug-in.
But after a while, this becomes natural, It becomes also more obvious
that in many cases you have code in a plug-in that you do not need to
export to other plug-ins.
[Image 15: Exported packages]
Once the plug-in project is created, you can create a single plug-in
JAR
from it as follows: Open
/META-INF/MANIFEST.MF
in the
project, select the Overview tab and scroll to its bottom right corner.
[Image 16: Export Wizard Launch]
Click on "Export Wizard" on the bottom right corner of the
Overview tab.
[Image 17: Export Wizard]
On the Wizard, as an export destination, select
C:\rsp\simplejars\sharedplugins\eclipse
;
this is where we keep all "simple" plug-in JARs for
deployment. Also select "Package plug-ins as individual JAR
archives". This will export the plug-in in non-exploded form. You
can see the generated plug-in JAR in the
C:\rsp\simplejars\sharedplugins\eclipse\plugins
folder. It will be picked up by our webapp through one of the entries
in
the
/WEB-INF/platform/links
folder.
We try not to have any "non-plug-in" jars floating around in
the deployed application. Some plug-ins have a
/jars
folder, but those JARs are not deployed, and only used as needed for
precompiling JSPs.
Dependency hierarchies and two-way dependencies
Attention: if the plug-in you just created itself depends on other
JARs
to run, you will have to add those as "Dependent JARs" on the
"Dependencies" tab, of
/META-INF/MANIFST.MF
before exporting it. If you did not do that, you will soon find out
when
you run the application, as you will get Class-not-found exceptions in
the Tomcat console. This happens because of the smart
class-loading/isolation rules of OSGi. At first you think it is a pain,
but after a while you really appreciate having the dependencies
explicit. Tip: if the library has been "mavenized" with Maven
2, you may find its dependencies documented in a Maven 2 repository.
The Eclipse IDE comes with a nifty editor on the "Dependency"
tab that lets you analyze your dependency graph and look for cycles in
your dependency graph.
[Image 18: Dependency Cycle Analysis]
Another thing to watch out for: Classes that are in a
"sub-dependent" plug-in do not automatically get exposed to
the top plug-in. Only if you select "Reexport this dependency"
on the Properties dialog of the list of Dependencies this should be the
case, but it didn't work for me as expected.
At this point, we can take a look at the raw descriptor generated by
all
the Eclipse graphical plug-in editors, used to describe the plug-in.
This is
/META-INF/MANIFEST.MF
[Image 19: MANIFEST.MF]
In this file you find Dependent (=Required) plug-ins listed under
Require-Bundle
,
you find packages exported under
Export-package
.
Sometimes you have cases where your dependency goes two ways. For
example, our plug-in
org.rsp.framework.struts
depends on
org.rsp.jar.commons_chain
,
because some classes are indirectly referenced by it. On the other
hand,
since commons_chain uses reflection to instantiate classes declared in
an xml configuration file (
chain-config.xml
) and not
contained in
org.rsp.jar.commons_chain
, it needs access
to
those classes to instantiate them. The suggested (Eclipse-specific)
mechanism to use here is called "
buddy classloading
".
You can make your plug-in's exported packages available to plug-ins
listed in a special registry. In our case, we added
Eclipse-BuddyPolicy:
registered
to the
MANIFEST.MF
of the
org.rsp.jar.commons_chain
plug-in, and
Eclipse-RegisterBuddy: org.rsp.jar.commons_chain
to the
MANIFEST.MF
of the
org.rsp.framework.struts
plug-in.
Working out dependencies took me a while, expect the same if you are
just starting.
Walkthrough of the Struts plug-ins
The interesting part of "OSGi-fying" Struts was of course that
individual plug-ins that use Struts should be capable of
"registering themselves" with the framework, without having to
hard-code a reference to each plug-in. Struts uses one or several
struts-config.xml
files that contain so-called "action mappings", which define
- what class or classes gets executed when a URL matching a certain
pattern is called (so-called "action URLs", such as "
/do/myAct
"
- which view/JSP to forward to (and return as a response) once the
action has been executed.
In "pre-OSGi" Struts, sub-modules had to be merged
declaratively, via the "
config
"
init-param
attribute in the struts action servlet definition of the webapp
web.xml
,
for example:
The Struts controller would parse the
param-value
, and
merge the configuration from the different
struts-config.xml
files.
What we were looking for was a way that the core Struts plug-in (
org.rsp.framework.struts
)
would be looking across the various plug-ins and "auto-load"
struts-config.xml
files across plug-ins.
We had several options to do this. One was to create our own extension
points. This is a bit involved, since you need to create an xml schema
for the definition of the extension point. Another one was to use
OSGi-native "declarative services" for registration. The third
one, most easily accessible, was to go via the existing
"resources" and "
httpcontexts
"
extension points, and construct URLs that permit the OSGified Struts to
load the resources from the different plug-ins. We chose the third
option.
So now, the Struts action servlet in
plugin.xml
of
org.rsp.framework.struts
is defined as follows:
You notice the wildcard "*" at the beginning of
param-value
.
This means that the BundleActionServlet will look for (and register)
all
resources at
/WEB-INF/struts-config.xml
in all bundles
using the "
httpcontexts
" Extension points,
ignoring those that don't happen to have one. As long as all
struts-using plug-ins keep their
struts-config.xml
files
in
that standard location, they will be registered with the Struts
controller in the
org.rsp.framework.struts
plug-in.
You can take a look at the implementation of this lookup mechanism in
BundleActionServlet
[
6
].
The end result is that you can write a JSP page which draws
functionality from multiple plug-ins that use Struts.
[Image 20: Struts demo]
This demo does not go all the way because there is still a physical JSP
in the webapp, which "has" the URLs of the plug-in resources
hardwired. If we were to add a declared "View" Extension to
each Struts plug-in, we could easily imagine a servlet, which composes
a
page dynamically from all plug-ins that have that Extension declared,
as
in an RCP app or the Eclipse IDE as an example for an RCP app. Then of
course the next item would be to define navigation menus declaratively
via extension points, or OSGi declarative services. The sky's the
limit!
And the Eclipse/OSGi server-side UI framework is near!
If you use another framework that declaratively brings together various
configuration files, you might implement it in a similar fashion.
Another important note: the demo is still very simple in the sense that
we do not use any heavy duty "non-UI" plug-ins. Imagine
reusing the "Eclipse Update manager" for provisioning all the
clients of your industrial plug-ins with updates to their server-side
applications.
Deployment
The quick run-through described under the heading "Learn-it"
above shows what you need to do so that changes to your plug-in(s) show
up in the running application. You may remember that we have Tomcat
point directly to the webapp
/WebContent
.
However, Tomcat only reads classes and jars in the
/WEB-INF/classes
and
/WEB-INF/lib
folders, so what
sp_redeploy
does is copy the plug-in JARs in
/platform/plugins
and
those referenced in the
/links
folder [
7
]
into Tomcats
/work/catalina/localhost/rspwebapp
folder where they are available to the
BridgeServlet
implementation. Tomcats
/work
folder is also where Tomcat
stores compiled JSPs.
At the time of writing, there is no automated mechanism to convert JSPs
INSIDE plug-ins into mapped classes. So what we have done is create a
precompile.xml
ant script, which needs to be executed before a particular plug-in is
"
JARred
" via the "
Export wizard
".
This is just a tiny bit painful, and gets in the way of development,
and
you still have to add each precompiled JSP into the
plugin.xml
with their servlet path. This precompilation script is
container-specific, but can be adapted (a working version already
exists
for Weblogic 9). We set precompilation to write Java files to a precomp
folder and class files directly to the root of the project (so in the
project you just see the
org
package).
On the deployment theme, what would be great is to not have to manually
execute the "
Export Wizard
" JARring of the
plug-in, while in development mode. While the Eclipse editor does not
have that feature "yet" (it exists for RSP plug-ins as
"Run as RCP app") we could augment the
FrameworkLauncher
(responsible for "
sp_redeploy
") to copy the
applicable parts of the project into Tomcat
/work
in
exploded form (for particular plug-ins only). All we would have to do
is
parse the
build.properties
, which contains the
information
what to copy during deployment using
/sp_redeploy
. This
is
open source, please come forward if you are interested in this feature
and have just a little time to spend.
At the moment, we make the redeployment task a little easier by having
dragged the
sp_redeploy
link onto the Links bar of the
browser. So we can just hit it when we want to refresh the webapp with
(Exported) plug-ins on the webapp.
[Image 21:
/sp_redeploy
via browser link: Drag link to
"Links" bar and drop there]
Nirwana of course would be a watcher, that picks up on changes in
plug-ins, and redeploys them automatically, so the browser will always
have the latest state. This is something even the Server manager in WTP
cannot do for webapps (it just always restarts Tomcat upon detected
changes, if I am not mistaken).
User session management
When we started, we found that
/sp_redeploy
would give
us
class-cast exceptions when we had items in the user session which came
from a redeployed bundle; this is not surprising. Tomcat has a feature
to deal with user session items upon webapp redeployment, but it does
not kick in here (we do not redeploy the webapp, we just redeploy
plug-ins inside the webapp).
One nice strategy would be to invalidate affected user sessions only,
or
even find a way to allow existing user sessions run on the old version.
Right now, we just brutally invalidate all user sessions upon
/sp_redeploy
,
so we can develop without a problem.
Conclusion
You can create an Eclipse/OSGi-fied webapp, with your own
web-enabled
plug-ins, probably by copying one of the existing sample or using them
as blueprints.
Someone has already taken this and created a Tapestry/Hivemind version,
which we hope to make available via SVN. Someone has run this on
Weblogic. What about the other containers? There is very little
container-specific stuff in here. How about running Flash/Laszlo this
way?
The ultimate goal may be to run all plug-ins in a native "OSGi
bundle container", removing the need for a J2EE/Servlet container
altogether.
- What are your ideas where this could lead?
I have set up a quicktopic thread for
your thoughts, comments, ideas, feedback and discussion
here
[
8
]
If you enjoyed hearing about this, and would be
interested in hearing more over time, please join the Infonoia
community
.
Note that you can opt out at any time by unselecting "You may email
me...".
Miscellaneous Tips and tricks
Make sure your exported JAR actually contains what you think. For
this, you can unzip the deployed jar (in Tomcats
/work/Catalina/localhost/rspwebapp/platform/plugins
folder and see what's there, and then fix it on the "
Build
"
tab of the plug-in Editor.
When you use the "Export Wizard", make sure you write the plug-in
to the right place. We set up a separate
/runtime
folder
as part of each project, except for simplejar plug-ins, and the equinox
plug-ins which go directly to the
/WEB-INF/platform/plugins
of the webapp. If you export into the wrong one, you may have several
copies around, and the old one around may be copied over the new one
during deployment (as they all end up in the
/platform/plugins
folder under Tomcat
/work
). What we did is to create an "
export.xml
"
ant task the first time we use the Export Wizard (there is an option
for that on the wizard). From then on, we launch that ant task by
selecting
export.xml
, and launch it with Shift+Alt+X, Q.
Always make sure that the packages you wish to make accessible
are listed as "
Exported Packages
" on the "
Runtime
"
tab of the plug-in.
[4] Under Linux, you may register the demo
webapp with Tomcat as
follows: Delete
$CATALINA_HOME%/conf/Catalina/localhost/rspwebapp.xml
.
Instead, in
$CATALINA_HOME$/webapps
, create a link to
rsp/workspace/org.rsp.sample.webapp/WebContent
.
The
rspDemo-xx.zip
includes Subclipse plug-ins for SVN
repository support (
http://subclipse.tigris.org
) for Windows. When you
have installed the Eclipse build for Linux, you may use the update
manager to install Subclipse for your platform. The update site is at
http://subclipse.tigris.org/update_1.0.x
[5] NOTE: as setup in
c:\rsp\apache-tomcat-5.5.15\conf\catalina\localhost\rspwebapp.xml
[6] This implementation requires calling
/sp_redeploy
(see section on deployment), notably reinitialization of
org.rsp.framework.struts
,
to discover resources in other Struts bundles. This will have to be
considered when moving to finer-grained deployment (where we deploy
individual bundles). At that point, an OSGi-native services
implementation under the hood of the registration mechanism
(framework.struts provides a "service", to which the Struts
bundles subscribe) may come to the rescue. To be covered by a future
article!
[7] A
.links
file in the
/links
directory make
the framework follow the path provided in that file. It will treat
files
from
/eclipse/plugins
and
/platform/plugins
under that target path the same way as if they were inside the
/plugins
directory which is the sibling to the
/links
directory.
Re: Developing Eclipse/OSGi Web Applications Part 2
Just run accross this article. It looks very interesting. General all-size-fits-all WAR is definetely hard to use for big projects.
Did you consider possible context plugin filtering? Say, user have permissions to only certain plugins and how to filter other extensions out? In some way this could be similar to the activities/capabilities concept in the Eclipse?
Developing Eclipse/OSGi Web Applications Part 2
At 10:44 AM on Feb 16, 2006, Riyad Kalla
wrote:
About the Author
About this Tutorial
This tutorial is split into two parts. The first part will cover a sample web application all the way to creating the necessary extension points for your own. The second part will pickup right where Part 1 left off and guide you through mapping your servlet, dependencies and then eventually running your new web application.
Introduction
Welcome to Part 2 of the OSGi Web Application tutorial. You should have read Part 1 by now and have everything setup appropriatley to continue working on our sample web application. We are going to dig right into extensions, servlets, resources and more. So let's get started!
Extensions and Extension points
Now let's look at the wizardry that creates these URL servlet and resource mappings behind the scenes from Part 1 . The magic is in the file

plugin.xmlincluded in each plug-in. It uses an Eclipse-specific mechanism (invented even before Eclipse migrated to OSGi infrastructure) called "Extensions" and "Extension points". Extensions provide a way to specify possible interactions between plug-ins.[Image 9: Extensions in the plug-in editor]
Extension points in Eclipse are what makes, for example menu items , show up on the menu bar (the
org.eclipse.ui.menusextension point, among others, for historical reasons, in this particular case). The menu renderer obtains the "Extensions" from the "Extension registry" and builds the menu from that information.Part of my vision for a "Eclipse/OSGi server-side UI framework is to use the same mechanism to build menus, views, editors etc. the same way for server-side applications. However, this demo app "just" uses the extension points to make HTTP output from different plug-ins accessible.
Note: Release 4 of the OSGi-standard provides a different mechanism called "declarative services" to achieve what the Eclipse-specific extensions do, and more. Eclipse 3.2 final is likely to support declarative services (since it's part of the OSGi-implentation Eclipse uses); but plug-in Editor support may only be for a later date.
Mapping servlets
Go to the project

org.rsp.framework.struts, openplugin.xml, select theplugin.xmltab and inspect it. You will find the following:[Image 10: PluginXmlServlet]
This is an Extension which provides the description for a servlet as you would normally find in your application's
WEB-INF/web.xml. The webapp has aweb.xml, but it is outside of this particular plug-in, and providing the mapping there would of course defeat the purpose of "component" plug-ins. [Note: You will find a web.xml also in/WEB-INF/of theorg.rsp.framework.strutsplug-in. However, it is only there to avoid errors during precompilation of JSPs, and otherwise defunct.] However, code in the webapp (in the Equinox plug-in jars, actually) reads the information from the Extensions, and registers the servlets described there in theBridgeServletshown earlier.The structure of servlet "extension points" is similar, but not quite identical to what you would find in a
web.xml.replacesandis new. The OSGi standard specifies that each HTTP service (used by theBridgeServlet, under the hood) uses a differentServletContext* unless theHttpContextis shared*. This could create problems in case of MVC forwards, where usually certain information is passed from the first servlet to the second via the request context. That transport would be broken under Eclipse-OSGi if different or "null" HttpContexts are used among the related servlets. The trick is to give all servlets and resources the same "httpcontext-name". The name of our choice is "cross-context" (alluding to the Tomcat server.xml attribute as incross-context="true", which does similar things but across web applications.).Now we know how a servlet is mapped from the bundle to the container. The same works for precompiled JSPs (more about precompiling below).
Mapping resources
How do we map a resource such as the stylesheet resource at


http://localhost/rspwebapp/platform/myresourcenamespace/css/my.cssmentioned earlier?[Image 11: PluginXmlResource]
This is a combination of two extension points. The "
httpcontexts" extension point specifies which directories in a plug-in JAR actually get exposed as a http resource. In our case, this is *everything* recursively under the/WebContentdirectory in the plug-in JAR.The "
resources" extension point specifies under what (sub)namespace this happens. Again, a "httpcontext-name" is given to allow sharing of context across plug-ins.Is this complicated? Well, we think that all three extension points could be rolled into one that more closely resembles a classic
web.xml, with just a namespace and context-path (/WebContent) added. Someone just needs to do it, this is open sourceMaybe, eventually, extension points get deprecated in favor of OSGi-standard "declarative services". Or wrapped. Now Eclipse uses a custom "extension point registry", for lookup . If a reader of this article is interested in implementing web.xml-style declarative services, please let me know.
Please do not forget that not everything that is seen in the Eclipse IDE plug-in project automatically goes into the plug-in JAR. The plug-in jar contents need to be specified on the "Build" tab of the plug-in editor.
[Image 12: Build tab]
Now we understand how resources are mapped from the bundle to the container, and what goes into a plug-in jar. One more important conceptual thing: Dependencies. The good news: it is downhill from there.
Dependencies
The OSGi specification recommends that a bundle is deployed as a single JAR. For the Eclipse IDE, most plug-ins (see the

C:\rsp\eclipse\pluginsfolder) are now single-JAR plug-ins. However, some plug-ins are "exploded" into the file system; however, single-JAR plug-ins are more performant. Moving to single-JAR plug-ins mostly is what made startup of the Eclipse Workbench faster in the latest releases. Single-JAR plug-ins have just one "problem": they cannot contain other JARs, while exploded plug-ins can. But there is a solution.More involved (=advanced) plug-ins will usually depend on the presence of other libraries (JARs) in the runtime environment. For example, the
org.rsp.sample.usage.customtaglibplug-in uses the displaytag libary, which is provided in a separate JAR. Could we just add that JAR inside the customtaglib plug-in? Yes, we could. We would just have to declare the JAR on the bundle classpath. Of course we would have to repeat that for every bundle which has that dependency. And we might end up with a maintenance nightmare.The clean solution is to make that dependent JAR a separate Eclipse plug-in, and declare it as a "Required Plug-in" for the plug-in that depends on it. You can do that on the "Dependencies" tab of
plugin.xmlof the plug-in that requires the other. (Boy, take a deep breath, read the first part of this paragraph again, and make sure you understand it before you go on, please).[Image 13: Dependencies for Customtaglib]
Creating "simple" plug-in JARs from existing JAR archives
Creating a plug-in JAR from an existing JAR archive is a two-step process: creating the plug-in project from the existing JAR archive, and "exporting" the plug-in as plug-in JAR archive.




You can create a plug-in from an existing JAR archive with the "
File/New/Other" Wizard "Plug-in Development/Plug-in from existing JAR archives".[Image 14: JAR Plugin Wizard]
We call plug-ins created from existing JAR archives "
Simplejar" plug-ins, and maintain them in the "Simplejar" Working Set. (Menu Window-Working Sets-Edit, select Simplejars, press Edit, and check the newly added project).By the way, just having code in a plug-in jar does not make that code accessible to other plug-ins that declare the dependency to this plug-in! You also need to make sure that the packages you wish to make accessible are listed as "Exported Packages" on the "Runtime" tab of the plug-in. In the Eclipse IDE, you can access the "Runtime" tab by opening either
build.properties,/META-INF/MANIFEST.MForplugin.xml(if available). The abovementioned wizard automatically creates entries in the "Exported Packages" list, so for simple plug-ins created from existing JAR archives this is less of an issue.But you are almost bound to forget this when you create your own plug-ins from scratch, or add new code packages to an existing plug-in. But after a while, this becomes natural, It becomes also more obvious that in many cases you have code in a plug-in that you do not need to export to other plug-ins.
[Image 15: Exported packages]
Once the plug-in project is created, you can create a single plug-in JAR from it as follows: Open
/META-INF/MANIFEST.MFin the project, select the Overview tab and scroll to its bottom right corner.[Image 16: Export Wizard Launch]
Click on "Export Wizard" on the bottom right corner of the Overview tab.
[Image 17: Export Wizard]
On the Wizard, as an export destination, select
C:\rsp\simplejars\sharedplugins\eclipse; this is where we keep all "simple" plug-in JARs for deployment. Also select "Package plug-ins as individual JAR archives". This will export the plug-in in non-exploded form. You can see the generated plug-in JAR in theC:\rsp\simplejars\sharedplugins\eclipse\pluginsfolder. It will be picked up by our webapp through one of the entries in the/WEB-INF/platform/linksfolder.We try not to have any "non-plug-in" jars floating around in the deployed application. Some plug-ins have a
/jarsfolder, but those JARs are not deployed, and only used as needed for precompiling JSPs.Dependency hierarchies and two-way dependencies
Attention: if the plug-in you just created itself depends on other JARs to run, you will have to add those as "Dependent JARs" on the "Dependencies" tab, of


/META-INF/MANIFST.MFbefore exporting it. If you did not do that, you will soon find out when you run the application, as you will get Class-not-found exceptions in the Tomcat console. This happens because of the smart class-loading/isolation rules of OSGi. At first you think it is a pain, but after a while you really appreciate having the dependencies explicit. Tip: if the library has been "mavenized" with Maven 2, you may find its dependencies documented in a Maven 2 repository.The Eclipse IDE comes with a nifty editor on the "Dependency" tab that lets you analyze your dependency graph and look for cycles in your dependency graph.
[Image 18: Dependency Cycle Analysis]
Another thing to watch out for: Classes that are in a "sub-dependent" plug-in do not automatically get exposed to the top plug-in. Only if you select "Reexport this dependency" on the Properties dialog of the list of Dependencies this should be the case, but it didn't work for me as expected.
At this point, we can take a look at the raw descriptor generated by all the Eclipse graphical plug-in editors, used to describe the plug-in. This is
/META-INF/MANIFEST.MF[Image 19: MANIFEST.MF]
In this file you find Dependent (=Required) plug-ins listed under
Require-Bundle, you find packages exported underExport-package.Sometimes you have cases where your dependency goes two ways. For example, our plug-in
org.rsp.framework.strutsdepends onorg.rsp.jar.commons_chain, because some classes are indirectly referenced by it. On the other hand, since commons_chain uses reflection to instantiate classes declared in an xml configuration file (chain-config.xml) and not contained inorg.rsp.jar.commons_chain, it needs access to those classes to instantiate them. The suggested (Eclipse-specific) mechanism to use here is called "buddy classloading". You can make your plug-in's exported packages available to plug-ins listed in a special registry. In our case, we addedEclipse-BuddyPolicy: registeredto theMANIFEST.MFof theorg.rsp.jar.commons_chainplug-in, andEclipse-RegisterBuddy: org.rsp.jar.commons_chainto theMANIFEST.MFof theorg.rsp.framework.strutsplug-in.Working out dependencies took me a while, expect the same if you are just starting.
Walkthrough of the Struts plug-ins
The interesting part of "OSGi-fying" Struts was of course that individual plug-ins that use Struts should be capable of "registering themselves" with the framework, without having to hard-code a reference to each plug-in. Struts uses one or several
struts-config.xmlfiles that contain so-called "action mappings", which define- what class or classes gets executed when a URL matching a certain pattern is called (so-called "action URLs", such as "
/do/myAct"- which view/JSP to forward to (and return as a response) once the action has been executed.
In "pre-OSGi" Struts, sub-modules had to be merged declaratively, via the "
config"init-paramattribute in the struts action servlet definition of the webappweb.xml, for example:<init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml, /WEB-INF/moduleA/struts-config.xml, /WEB-INF/moduleB/struts-config.xml </param-value> </init-param>The Struts controller would parse theparam-value, and merge the configuration from the differentstruts-config.xmlfiles.What we were looking for was a way that the core Struts plug-in (
org.rsp.framework.struts) would be looking across the various plug-ins and "auto-load"struts-config.xmlfiles across plug-ins.We had several options to do this. One was to create our own extension points. This is a bit involved, since you need to create an xml schema for the definition of the extension point. Another one was to use OSGi-native "declarative services" for registration. The third one, most easily accessible, was to go via the existing "resources" and "
httpcontexts" extension points, and construct URLs that permit the OSGified Struts to load the resources from the different plug-ins. We chose the third option.So now, the Struts action servlet in
plugin.xmloforg.rsp.framework.strutsis defined as follows:<alias>/do</alias> <servlet-class>org.rsp.framework.struts.base.BundleActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>*/WEB-INF/struts-config.xml</param-value> </init-param> </servlet-class>You notice the wildcard "*" at the beginning ofparam-value. This means that the BundleActionServlet will look for (and register) all resources at/WEB-INF/struts-config.xmlin all bundles using the "httpcontexts" Extension points, ignoring those that don't happen to have one. As long as all struts-using plug-ins keep theirstruts-config.xmlfiles in that standard location, they will be registered with the Struts controller in theorg.rsp.framework.strutsplug-in.You can take a look at the implementation of this lookup mechanism in
BundleActionServlet[ 6 ].The end result is that you can write a JSP page which draws functionality from multiple plug-ins that use Struts.
[Image 20: Struts demo]
This demo does not go all the way because there is still a physical JSP in the webapp, which "has" the URLs of the plug-in resources hardwired. If we were to add a declared "View" Extension to each Struts plug-in, we could easily imagine a servlet, which composes a page dynamically from all plug-ins that have that Extension declared, as in an RCP app or the Eclipse IDE as an example for an RCP app. Then of course the next item would be to define navigation menus declaratively via extension points, or OSGi declarative services. The sky's the limit! And the Eclipse/OSGi server-side UI framework is near!
If you use another framework that declaratively brings together various configuration files, you might implement it in a similar fashion.
Another important note: the demo is still very simple in the sense that we do not use any heavy duty "non-UI" plug-ins. Imagine reusing the "Eclipse Update manager" for provisioning all the clients of your industrial plug-ins with updates to their server-side applications.
Deployment
The quick run-through described under the heading "Learn-it" above shows what you need to do so that changes to your plug-in(s) show up in the running application. You may remember that we have Tomcat point directly to the webapp

/WebContent.However, Tomcat only reads classes and jars in the
/WEB-INF/classesand/WEB-INF/libfolders, so whatsp_redeploydoes is copy the plug-in JARs in/platform/pluginsand those referenced in the/linksfolder [ 7 ] into Tomcats/work/catalina/localhost/rspwebappfolder where they are available to theBridgeServletimplementation. Tomcats/workfolder is also where Tomcat stores compiled JSPs.At the time of writing, there is no automated mechanism to convert JSPs INSIDE plug-ins into mapped classes. So what we have done is create a
precompile.xmlant script, which needs to be executed before a particular plug-in is "JARred" via the "Export wizard". This is just a tiny bit painful, and gets in the way of development, and you still have to add each precompiled JSP into theplugin.xmlwith their servlet path. This precompilation script is container-specific, but can be adapted (a working version already exists for Weblogic 9). We set precompilation to write Java files to a precomp folder and class files directly to the root of the project (so in the project you just see theorgpackage).On the deployment theme, what would be great is to not have to manually execute the "
Export Wizard" JARring of the plug-in, while in development mode. While the Eclipse editor does not have that feature "yet" (it exists for RSP plug-ins as "Run as RCP app") we could augment theFrameworkLauncher(responsible for "sp_redeploy") to copy the applicable parts of the project into Tomcat/workin exploded form (for particular plug-ins only). All we would have to do is parse thebuild.properties, which contains the information what to copy during deployment using/sp_redeploy. This is open source, please come forward if you are interested in this feature and have just a little time to spend.At the moment, we make the redeployment task a little easier by having dragged the
sp_redeploylink onto the Links bar of the browser. So we can just hit it when we want to refresh the webapp with (Exported) plug-ins on the webapp.[Image 21:
/sp_redeployvia browser link: Drag link to "Links" bar and drop there]Nirwana of course would be a watcher, that picks up on changes in plug-ins, and redeploys them automatically, so the browser will always have the latest state. This is something even the Server manager in WTP cannot do for webapps (it just always restarts Tomcat upon detected changes, if I am not mistaken).
User session management
When we started, we found that
/sp_redeploywould give us class-cast exceptions when we had items in the user session which came from a redeployed bundle; this is not surprising. Tomcat has a feature to deal with user session items upon webapp redeployment, but it does not kick in here (we do not redeploy the webapp, we just redeploy plug-ins inside the webapp).One nice strategy would be to invalidate affected user sessions only, or even find a way to allow existing user sessions run on the old version. Right now, we just brutally invalidate all user sessions upon
/sp_redeploy, so we can develop without a problem.Conclusion
You can create an Eclipse/OSGi-fied webapp, with your own web-enabled plug-ins, probably by copying one of the existing sample or using them as blueprints.
Someone has already taken this and created a Tapestry/Hivemind version, which we hope to make available via SVN. Someone has run this on Weblogic. What about the other containers? There is very little container-specific stuff in here. How about running Flash/Laszlo this way?
The ultimate goal may be to run all plug-ins in a native "OSGi bundle container", removing the need for a J2EE/Servlet container altogether.
- What are your ideas where this could lead?
If you enjoyed hearing about this, and would be interested in hearing more over time, please join the Infonoia community . Note that you can opt out at any time by unselecting "You may email me...".
Miscellaneous Tips and tricks
/work/Catalina/localhost/rspwebapp/platform/pluginsfolder and see what's there, and then fix it on the "Build" tab of the plug-in Editor./runtimefolder as part of each project, except for simplejar plug-ins, and the equinox plug-ins which go directly to the/WEB-INF/platform/pluginsof the webapp. If you export into the wrong one, you may have several copies around, and the old one around may be copied over the new one during deployment (as they all end up in the/platform/pluginsfolder under Tomcat/work). What we did is to create an "export.xml" ant task the first time we use the Export Wizard (there is an option for that on the wizard). From then on, we launch that ant task by selectingexport.xml, and launch it with Shift+Alt+X, Q.Exported Packages" on the "Runtime" tab of the plug-in.Enjoy! Wolfgang Gehner
www.infonoia.com
wgehner at infonoia dot com
This Tutorial was reviewed by: Martin Schikowski, Richard Backhouse, Simon Kaegi, Jim D'Anjou, Peter Neubauer and Ricardo Giacomin
References
[1] http://www.infonoia.com/en/content.jsp?d=inf.05.07
[2] http://sourceforge.net/project/showfiles.php?group_id=122298&package_id=176796&release_id=393605
[3] http://download.eclipse.org/eclipse/downloads/drops/S-3.2M4-200512151506/
[4] Under Linux, you may register the demo webapp with Tomcat as follows: Delete
$CATALINA_HOME%/conf/Catalina/localhost/rspwebapp.xml. Instead, in$CATALINA_HOME$/webapps, create a link torsp/workspace/org.rsp.sample.webapp/WebContent.The
rspDemo-xx.zipincludes Subclipse plug-ins for SVN repository support ( http://subclipse.tigris.org ) for Windows. When you have installed the Eclipse build for Linux, you may use the update manager to install Subclipse for your platform. The update site is at http://subclipse.tigris.org/update_1.0.x[5] NOTE: as setup in
c:\rsp\apache-tomcat-5.5.15\conf\catalina\localhost\rspwebapp.xml[6] This implementation requires calling
/sp_redeploy(see section on deployment), notably reinitialization oforg.rsp.framework.struts, to discover resources in other Struts bundles. This will have to be considered when moving to finer-grained deployment (where we deploy individual bundles). At that point, an OSGi-native services implementation under the hood of the registration mechanism (framework.struts provides a "service", to which the Struts bundles subscribe) may come to the rescue. To be covered by a future article![7] A
.linksfile in the/linksdirectory make the framework follow the path provided in that file. It will treat files from/eclipse/pluginsand/platform/pluginsunder that target path the same way as if they were inside the/pluginsdirectory which is the sibling to the/linksdirectory.[8] http://www.quicktopic.com/35/H/giqGy52F8Nk8b
[9] For further reading and links, see the article at http://www.infonoia.com/en/content.jsp?d=inf.05.07
[Image 22: OSGi schema]
1 replies so far (
Post your own)
Re: Developing Eclipse/OSGi Web Applications Part 2
Just run accross this article. It looks very interesting. General all-size-fits-all WAR is definetely hard to use for big projects.Did you consider possible context plugin filtering? Say, user have permissions to only certain plugins and how to filter other extensions out? In some way this could be similar to the activities/capabilities concept in the Eclipse?