Wednesday, December 9, 2009

JBossOSGi 1.0.0.Beta5 Released

I am happy to announce the release of JBossOSGi-1.0.0.Beta5.

You can download the binary here: jboss-osgi-installer-1.0.0.Beta5.jar

The release comes with improvements in the following areas
For details please have a look at the latest version of our User Guide.

Here are the change log details

Bug
  • [JBOSGI-129] - Filter behaviour change in r4v42
  • [JBOSGI-137] - Cannot parse Bundle-SymbolicName
  • [JBOSGI-153] - Cannot parse Import-Package parameters
  • [JBOSGI-187] - Husky SocketInvocation may block forever
  • [JBOSGI-199] - Use thread safe collections where information is mutable
  • [JBOSGI-212] - Cannot refresh Microcontainer service
Feature Request

  • [JBOSGI-125] - Add ManagedFramework service
  • [JBOSGI-202] - Allow override of where the bootstrap file comes from
Task
  • [JBOSGI-157] - JTA (RFC-98) - Initial Implementation
  • [JBOSGI-181] - Add EventAdmin as available service
  • [JBOSGI-182] - Release JBoss OSGi 1.0.0.Beta5
  • [JBOSGI-183] - Introduce notion of OSGi Interceptors
  • [JBOSGI-188] - Separate DeployerService from SPI
  • [JBOSGI-190] - Allign getting started guide with latest release
  • [JBOSGI-200] - Split getParameter(s) calls into directives/attributes
  • [JBOSGI-215] - Update Blueprint to 1.0.0.Alpha3
  • [JBOSGI-216] - Update to Apache Felix-2.0.2
  • [JBOSGI-217] - Update to Eclipse Equinox-3.5.1
  • [JBOSGI-218] - Update to jboss-osgi-common-1.0.3
  • [JBOSGI-219] - Update to jboss-osgi-husky-1.0.2
  • [JBOSGI-220] - Update to jboss-osgi-jmx-1.0.2
  • [JBOSGI-221] - Update to jboss-osgi-jndi-1.0.2
  • [JBOSGI-222] - Update to jboss-osgi-microcontainer-2.0.9
  • [JBOSGI-223] - Update to jboss-osgi-spi-1.0.3
  • [JBOSGI-224] - Update to jboss-osgi-xml-binding-2.0.2.Beta3
  • [JBOSGI-225] - Update to jboss-osgi-apache-xerces-2.9.1.SP3
  • [JBOSGI-226] - Update to jboss-osgi-hotdeploy-1.0.3
  • [JBOSGI-227] - Update to jboss-osgi-framework-1.0.0.Alpha2
  • [JBOSGI-228] - Update to jboss-osgi-jaxb-2.1.10.SP3
  • [JBOSGI-229] - Add jboss-osgi-deployment-1.0.0
  • [JBOSGI-230] - Add jboss-osgi-jta-1.0.0
  • [JBOSGI-231] - Add jboss-osgi-reflect-2.0.2
  • [JBOSGI-232] - Add jboss-osgi-webapp-0.7.2
  • [JBOSGI-233] - Update to org.apache.felix.configadmin-1.2.4
  • [JBOSGI-234] - Add org.apache.felix.eventadmin-1.0.0
Enjoy

Tuesday, November 3, 2009

OSGi Framework Launch

In this post I am going to look at the problems involved when you need to launch an OSGi Framework independent of the actual Framework implementation. There will be coverage of
  • Framework Launch API
  • OSGi Bootstrap abstraction
The Framework Launch API

Starting with Version 1.5 of the Framework API, which is part of the core r4v42 specification, OSGi comes with the ability to launch an OSGi Framework in an implementation agnostic manner. For this, clients interact with the classes in package org.osgi.framework.launch like this

// Load the framework factory
FrameworkFactory factory = loadFrameworkFactory();

// Load the framework configuration
Map config = loadFrameworkConfig();

// Create a new instance of the framework
Framework framework = factory.newFramework(config);
try
{
   // Start the framework
   framework.start();

   // do stuff
}
finally
{
   // Stop the framework
   framework.stop();

   // Wait for the framework to stop completely
   framework.waitForStop(3000);
}


As you can see, this API is fairly low level. The client provides code that loads the FrameworkFactory, as well as code that obtains the Framework configuration somehow. At this level, there is no API or standard config that defines initial bundle provisioning.

OSGi Bootstrap abstraction

If you are running on JDK-1.6 there is a ServiceLoader available that can be used to load the FrameworkFactory like this

// Load the framwork factory
ServiceLoader loader = ServiceLoader.load(FrameworkFactory.class);
FrameworkFactory factory = loader.iterator().next();

// Create a new instance of the framework
Framework framework = factory.newFramework(null);


Since this API might not be available in every environment, JBoss OSGi also provides a ServiceLoader as part of its Service Provider Interface (SPI). Conceptually very similar, here is how you would use this API

// Load the framework factoryFramework
Factory factory = ServiceLoader.load(FrameworkFactory.class);

// Create a new instance of the framework
Framework framework = factory.newFramework(null);


Both variants of the service loader provide you with an instance of FrameworkFactory from which you can now use to create a new Framework instance. The null parameter causes the Framework to use it's default configuration.

The JBoss OSGi SPI supports a Framework bootstrap process based on unified configuration files. In its most simple form the usage of this API would look like this

// Get the configured bootstrap provider
OSGiBootstrapProvider bootProvider = OSGiBootstrap.getBootstrapProvider();

// Get the configured framework from the boot provider
Framework framework = bootProvider.getFramework();


An OSGiBootstrapProvider is an abstraction of a provider that can somehow bootstrap an OSGi Framework. A concrete implementation and also the default that is used if no other provider is configured is the PropertiesBootstrapProvider. As the name suggests, this bootstrap provider can be configured using a plain java properties file. The default location of this file is a resource called jboss-osgi-framework.properties loadable from the bootstrap classpath.

An example of such a properties file is shown below

# Extra server specific properties
org.jboss.osgi.spi.framework.extra=${somedir}/osgi-extra.properties

# Properties to configure the Framework
org.osgi.framework.storage=${osgi.server.home}/data/osgi-store
org.osgi.framework.storage.clean=onFirstInit

# Hot Deployement
org.jboss.osgi.hotdeploy.scandir=${osgi.server.home}/deploy

# Bundles that need to be installed with the Framework automatically
org.jboss.osgi.spi.framework.autoInstall=\
file://${osgi.home}/server/minimal/deploy/org.osgi.compendium.jar

# Bundles that need to be started automatically 
org.jboss.osgi.spi.framework.autoStart=\
file://${osgi.home}/server/minimal/deploy/org.apache.felix.log.jar \
file://${osgi.home}/server/minimal/deploy/jboss-osgi-common.jar \
file://${osgi.home}/server/minimal/deploy/jboss-osgi-hotdeploy.jar


Noteworthy, are perhaps the properties that can be used for initial framework provisioning
and the extension point that allows to recursively split the properties over multiple files
All other properties are simply passed on the FrameworkFactory.newFramework(Map config) method.

We looked at the basic OSGi Framework launch API and have seen how to externalize Framework configuration to property files. Other bootstrap providers could work of your favourite XML dialect. For the Apache Felix JBossAS integration we use a jboss-beans.xml configuration.

With my next post I am going to start a series of Enterprise OSGi topics. There should be coverage of JTA, JMX, JNDI, WebApp and perhaps others.

May this be useful

Friday, October 23, 2009

Extender Pattern vs. Lifecycle Interceptor

With this post I'd like to give a little more background on the well known OSGi Extender Pattern, when this pattern is applicable and what might be an alternative when it is not applicable. There will be coverage of
  • Basics of extending an OSGi Bundle
  • Advantages and drawbacks of Extenders
  • Notion of "self ordering" LifecycleInterceptor
Extending an OSGi Bundle

The basic functional sequence of an OSGi Extender goes like this
  1. Extender registers itself as BundleListener
  2. Bundle gets installed/started
  3. Framework fires a BundleEvent
  4. Extender picks up the BundleEvent (e.g. STARTING)
  5. Extender reads metadata from the Bundle and does its work
There is no extender specific API. It is a pattern rather than a piece of functionality provided by the Framework. Typical examples of extenders are the Blueprint or Web Application Extender.

The following illustration shows how a WAR Extender might process an OSGi Web Application to register servlets that are declared in WEB-INF/web.xml with the OSGi HttpService.




Client code that installs, starts and uses the registered endpoint could look like this

// Install and start the Web Application bundle
Bundle bundle = context.installBundle("mywebapp.war");
bundle.start();

// Access the Web Application
String response = getHttpResponse("http://localhost:8090/mywebapp/foo");
assertEquals("ok", response);


This seemingly trivial code snippet has a number of issues that are probably worth looking into in more detail
  • The WAR might have missing or invalid web metadata (i.e. an invalid WEB-INF/web.xml descriptor)
  • The WAR Extender might not be present in the system
  • There might be multiple WAR Extenders present in the system
  • Code assumes that the endpoint is available on return of bundle.start()
It should be noted that the Extender, which is essentially a synchronous or asynchronous BundleListener has no way to veto the install or start transition of the bundle. Even if the Extender cannot process the metadata or fails for some other reason, the bundle will start just the same. Client code would see an ACTIVE bundle, which in fact might not be active at all in the colloquial sense of the word.

Most Blueprint or WebApp bundles are not useful if their Blueprint/Web metadata is not processed. Even if they are processed but in the "wrong" order a user might see unexpected results (i.e. the webapp processes the first request before the underlying Blueprint app is wired together).

As a consequence I would say that the extender pattern is useful in some cases but not all. IMHO it is mainly useful if a bundle can optionally be extended in the true sense of the word.

There is an RFP in the works that addresses many of the above issues. Adrian Colyer from SpringSource has initiated the work around RFP-118 Multiple Extenders in Nov-2008. The document is currently in the non-public review phase of the OSGi Alliance Enterprise Expert Group. (EEG)

Intercepting the Bundle Lifecycle

If the use case requires the notion of "interceptor" the extender pattern is less useful. The use case might be such that you would want to intercept the bundle lifecycle at various phases to do mandatory metadata processing.

An interceptor could be used for annotation processing, byte code weaving, and other non-optional/optional metadata processing steps. Traditionally interceptors have a relative order, can communicate with each other, veto progress, etc.

Lets look at how multiple interceptors can be used to create Web metadata and publish endpoints on the HttpService based on that metadata.



Here is how it works
  1. The Wep Application processor registers two LifecycleInterceptors with the LifecycleInterceptorService
  2. The Parser interceptor declares no required input and WebApp metadata as produced output
  3. The Publisher interceptor declares WebApp metadata as required input
  4. The LifecycleInterceptorService reorders all registered interceptors according to their input/output requirements and relative order
  5. The WAR Bundle gets installed and started
  6. The Framework calls the LifecycleInterceptorService prior to the actual state change
  7. The LifecycleInterceptorService calls each interceptor in the chain
  8. The Parser interceptor processes WEB-INF/web.xml in the invoke(int state, InvocationContext context) method and attaches WebApp metadata to the InvocationContext
  9. The Publisher interceptor is only called when the InvocationContext has WebApp metadata attached. If so, it publishes the endpoint from the WebApp metadata
  10. If no interceptor throws an Exception the Framework changes the Bundle state and fires the BundleEvent.
Client code is identical to above.

// Install and start the Web Application bundle
Bundle bundle = context.installBundle("mywebapp.war");
bundle.start();

// Access the Web Application
String response = getHttpResponse("http://localhost:8090/mywebapp/foo");
assertEquals("ok", response);


The behaviour of that code however, is not only different but also provides a more natural user experience.
  • Bundle.start() fails if WEB-INF/web.xml is invalid
  • An interceptor could fail if web.xml is not present
  • The Publisher interceptor could fail if the HttpService is not present
  • Multiple Parser interceptors would work mutually exclusiv on the presents of attached WebApp metadata
  • The endpoint is guaranteed to be available when Bundle.start() returns
The general idea is that each interceptor takes care of a particular aspect of processing during state changes. In the example above WebApp metadata might get provided by an interceptor that scans annotations or by another one that generates the metadata in memory. The Publisher interceptor would not know nor care who attached the WebApp metadata object, its task is to consume the WebApp metadata and publish endpoints from it.

The current BundleContext API does not allow for arbitrary attachments as contextual information to be passed between interceptors. The InvocationContext adds that plus the notion of a VirtualFile that represents the Bundle's content. The VirtualFile is necessary to access arbitrarily deeply nested resources regardless of their actual location.

Here a sneak preview of the ParserInterceptor that will come as part of the Interceptor example in JBoss OSGi 1.0.0.Beta5

public void invoke(int state, InvocationContext context)
{
  // Do nothing if the metadata is already available  
  HttpMetadata metadata = context.getAttachment(HttpMetadata.class);
  if (metadata != null)
    return;

  // Parse and create metadta on STARTING
  if (state == Bundle.STARTING)
  {
    try
    {
      VirtualFile root = context.getRoot();
      VirtualFile propsFile = root.getChild("/metadata.properties");
      if (propsFile != null)
      {
        log.info("Create and attach HttpMetadata");
        metadata = createHttpMetadata(propsFile);
        context.addAttachment(HttpMetadata.class, metadata);
      }
    }
    catch (IOException ex)
    {
      throw new LifecycleInterceptorException(ex);
    }
  }
}


and here the associate PublisherInterceptor

public void invoke(int state, InvocationContext context)
{
  // HttpMetadata is guaratied to be available because we registered
  // this type as required input
  HttpMetadata metadata = context.getAttachment(HttpMetadata.class);

  // Register HttpMetadata on STARTING 
  if (state == Bundle.STARTING)
  {
    String servletName = metadata.getServletName();
    try
    {
      log.info("Publish HttpMetadata: " + metadata);

      // Load the endpoint servlet from the bundle
      Bundle bundle = context.getBundle();
      Class servletClass = bundle.loadClass(servletName);
      HttpServlet servlet = (HttpServlet)servletClass.newInstance();

      // Register the servlet with the HttpService
      HttpService httpService = getHttpService(context, true);
      httpService.registerServlet("/servlet", servlet, null, null);
    }
    catch (RuntimeException rte)
    {
      throw rte;
    }
    catch (Exception ex)
    {
      throw new LifecycleInterceptorException(ex);
    }
  }

  // Unregister the endpoint on STOPPING 
  else if (state == Bundle.STOPPING)
  {
    log.info("Unpublish HttpMetadata: " + metadata);
    HttpService httpService = getHttpService(context, false);
    if (httpService != null)
      httpService.unregister("/servlet");
  }
}


This post and the initial implementation that is based on these concepts is a follow up of a discussion that I had with Hal Hildebrand from Oracle at one of our recent OSGi EEG meetings. Please stay tuned to find out in what shape or form these ideas develop.

In parallel to the standards efforts you will of course get this functionality as part of the next JBoss OSGi release, which should come out 01-Dec-2009.

That's it for now. In my next post I will explore the Framework launch API in more detail and show how you can bootstrap an OSGi Framework independent of the actual Framework implementation.

May this be useful.

Wednesday, October 14, 2009

JBossOSGi 1.0.0.Beta4 Released

I am happy to announce the release of JBossOSGi-1.0.0.Beta4.

You can download the binary here: jboss-osgi-installer-1.0.0.Beta4.jar

The release comes with improvements in the following areas
For details please have a look at the latest version of our User Guide.

Here are the change log details

Feature Request

  • [JBOSGI-110] - Support WAR deployments in the OSGi runtime
  • [JBOSGI-127] - Provide build and hudson support for MC facade
  • [JBOSGI-128] - Add Framework launch API

Task

Bug

  • [JBOSGI-78] - ResourceNotFoundException too verbose
  • [JBOSGI-130] - Bundle is still in state INSTALLED after bundle.start()
  • [JBOSGI-135] - Cannot handle package being imported and exported by the same bundle
  • [JBOSGI-136] - Cannot resolve dependency against unstarted bundle
  • [JBOSGI-140] - Invalid delivery of framework events
  • [JBOSGI-144] - Framework does not handle ServiceFactory provided services properly
  • [JBOSGI-151] - Cannot resolve circular dependencies
  • [JBOSGI-155] - OutOfMemoryError on repeated install/unstall bundle
  • [JBOSGI-158] - Framework itself must be a bundle
  • [JBOSGI-161] - Cannot use commons-logging
  • [JBOSGI-162] - Cannot load classes from Bundle-ClassPath
  • [JBOSGI-163] - Husky invocation before async extender processing

Enjoy

OSGi Unit Testing

With this post I'd like to give a little more background on OSGi unit testing. There will be coverage of
  • Basic problem of OSGi bundle testing
  • Running a unit test inside an OSGi Framework
  • Interaction between a test runner and the OSGi Framework
Introduction

One of the main characteristics of an OSGi environment is its high dynamicity. Services come and go at any time or get updated by newer versions. To verify that functionality provided by an OSGi Bundle does indeed behave as expected, you need good test coverage of that functionality. This of course is a general truth that is not limited to OSGi alone.

The benefit of unit testing is to isolate functionality and show that it behaves as expected. A unit test provides a strict, written contract that the piece of code must satisfy.

The basic problem in OSGi is that you cannot access the artefacts that you deploy in a bundle directly from the test case that runs external to the OSGi Framework. The test case is loaded from different classloader than the artefacts contained in the bundle.



Embedded OSGi Framework

This is probably the most common usage. A test or a wrapper around a collection of tests bootstraps the OSGi Framework installs a number of bundles and verifies their correct behaviour. Husky test cases leverage the OSGi Framework Launch API. Framework launching should not require prior knowledge of the actual framework implementation. OSGi Framework and test runner share the same VM. From the perspective of the test runner, the test can be executed like an ordinary unit test, which gives the developer the freedom of choice with respect to the runner (i.e. Eclipse, IntelliJ, Maven, Ant). The test reports results back to the runner like an ordinary unit test, which preserves the runner's test report functionality.

Remote OSGi Framework

In an enterprise scenario the OSGi Framework is more often than not a standalone container. The same test as above should be deployable in a remote framework that is already running. It is a configuration option of the test environment of whether the test gets installed into an embedded OSGi Framework or deployed to a remote framework instance. OSGi Framework and test runner do not share the same VM. From the perspective of the test runner, the test can still be executed like an ordinary unit test and it is completely transparent that the test gets actually executed in a remote environment. Conceptually, this is similar to what Apache Cactus is about.


Requirements
  1. The solution MUST support plain JUnit4 POJO test cases
  2. There SHOULD be no requirement to extend a specific test base class
  3. There MUST be no requirement on a specific test runner
  4. There SHOULD be a minimum test framework leakage into the test case
  5. The test framework MUST support embedded and remote OSGi Runtimes with no change required to the test
  6. The same test case MUST be executable from outside as well as from within the OSGi Framework
  7. There SHOULD be a pluggable communication layer from the test runner to the OSGi Framework
  8. The test framework MUST NOT depend on OSGi Framework specific features
  9. There MUST be no automated creation of test bundles required by the test framework
Architecture

JBoss OSGi Husky has client side interceptor that fields the test request to an embedded/remote OSGi Framework where the test case is then actually executed.



How does it work
  1. A Bridge intercepts a test and determines the FQN of the test case and the test method from the call stack. It then delegates the execution to the same (or another) test in and isolated test environment. An isolated test environment is one that does not have the same class loading space as the test itself.
  2. A Bridge is associated with an Invoker. Invokers may be arbitarily complex. Local 'in proccess' invokers are possible just as well as remote invokers.
  3. The Invoker sends the Request to a Connector in the isolated test environment.
  4. A Connector has associated PackageListeners that are responsible for processing test cases for their respective test packages.
  5. A PackageListeners delegates the Request to a test Runner, typicaly this would be a JUnitRunner.
  6. The Runner injects the Context into the test case and returns a Response, which the Connector returns to the Invoker.
  7. The Bridge finally translates potential Failures that may be contained in the Result, to test failures on the client side.
The JBoss OSGi jboss-osgi-husky.jar bundle registers the Connectors. The JMXConnector is always registered. The SocketConnector is registered when the appropriate configuration options are set. It then registers the HuskyExtender, which is a BundleListener that inspects every incomming bundle for the Test-Package manifest header. The Extender creates a PackageListener for every package in the 'Test-Package' manifest header and registers them with the available Connectors.

Configuration

In the target OSGi Framework, which is the one that has the jboss-osgi-husky.jar bundle installed, you set these properties.
# Husky socket connector properties
org.jboss.osgi.husky.runtime.connector.host=localhost
org.jboss.osgi.husky.runtime.connector.port=5401
Both properties must be set for the SocketConnector to be available.

On the client side, you configure the Invoker that you want to use.
# Husky invoker properties
org.jboss.osgi.husky.invoker=org.jboss.osgi.husky.internal.OSGiInvoker

This particular invoker will also look for the host and port properties and if availbale will use socket invocation.

Writing Husky Tests

In a typical Husky test you have
  • A discriminator to distinguish between client and 'in container' execution
  • An interceptor that delegates the call to an Invoker
For OSGi, the "discriminator" would be the BundleContext that gets injected by the 'in container' test Runner. The "interceptor" would be a call to one of the Bridge.run() variants.

public class SimpleHuskyTestCase
{
@ProvideContext
public BundleContext context;

...

@Test
public void testSimpleBundle() throws Exception
{
// Tell Husky to run this test method within the OSGi Runtime
if (context == null)
BridgeFactory.getBridge().run();


// Stop here if the context is not injected
assumeNotNull(context);

// Get the SimpleService reference
ServiceReference sref = context.getServiceReference("SimpleService");
assertNotNull("SimpleService Not Null", sref);

// Access the SimpleService
SimpleService service = (SimpleService)context.getService(sref);
assertEquals("hello", service.echo("hello"));
}
}

The bundle that contains the test case must have the Test-Package manifest header configured.
Bundle-SymbolicName: example-simple-husky

# Export the package that contains the test case
Export-Package: org.jboss.test.osgi.example.simple

# Tell Husky that there are test cases in this package
Test-Package: org.jboss.test.osgi.example.simple
That's it for now. JBoss OSGi 1.0.0.Beta4 is ready and waiting for the files to show up on Sourceforge. In a follow up post you can read about our new native OSGi Framework implementation that is based on the JBoss Microcontainer and how JBoss OSGi uses Pax Web to provide support for OSGi WebApps.

May this be useful

Friday, July 24, 2009

JBossOSGi 1.0.0.Beta3 Released

I am happy to announce the release of JBossOSGi-1.0.0.Beta3.

You can download it here: jboss-osgi-installer-1.0.0.Beta3.ja

The release comes with improvements in the following areas
For details please have a look at the latest version of our User Guide.

Here are the change log details

Feature Requests
  • [JBOSGI-93] - Uninstall bundles on OSGiRuntime.shutdown()
  • [JBOSGI-98] - Support configuration per profile
  • [JBOSGI-102] - Add support for static Husky context injection

Tasks

Bugs
  • [JBOSGI-66] - Support bundle deployment through web console
  • [JBOSGI-92] - Class.forName issue with XMLParserActivator
  • [JBOSGI-99] - No explicit control over bundle.start()
  • [JBOSGI-107] - MC beans cannot be redeployed after refresh

Enjoy

Friday, June 5, 2009

JBoss OSGi Runtime & JBossAS Integration

Now that JBoss OSGi 1.0.0.Beta2 is out I thought I'll explain a little more in detail what the various JBoss OSGi runtime models are about. In this post I'll cover
JBossAS has always been good at integrating loosely coupled services. In the 3.x and 4.x series that was done via a JMX based kernel in the 5.x series the AS switched to a Microcontainer based kernel. For JBoss OSGi only the 5.x series is relevenant so lets start with that.

Integration in JBossAS-5.x

Like any other service JBoss OSGi is integrated via a *-beans.xml descriptor.

More specifically, when you choose JBossAS integration in the Installer you will find and 'osgi.deployer' directory together with all your other MC deployers.

Deployers must be loaded first because as their name nicely suggests they deploy other services and applications. There is a lot to say about deployers, but lets focus on the JBoss OSGi specific osgi-deployers-jboss-beans.xml beans descriptor. Here you'll find all OSGi relevevant configuration options. For this post I'll take the Apache Felix integration as an example. There is however a similar beans descriptor for Equinox and Knopflerfish.

Without going in too much detail there are various beans configurations
  • OSGi Framework Integration
  • Bundle Management (JMX) Service
  • MC Integration Service
  • OSGi Deployers
Every time you deploy a bundle (i.e. drop it into the 'deploy' folder), the bundle gets processed by the OSGi Deployers, each of them taking care of a specific deployment aspect.

The JBoss OSGi AS integration looks something like this

You will notice that all the interesting AS provided services are 'outside' the OSGi world. You can think of them as 'system services' like the ones provided by the JVM itself. Hence a bundle wanting to access EJB, JTA, JPA, etc. can only do so if the packages that it imports are defined on the OSGi System Classpath. This would be the content of the 'org.osgi.framework.system.packages' property, which for Felix is currently defined like this

<key>org.osgi.framework.system.packages.extra</key>
<value>

<!-- system -->
org.apache.xerces.dom,

<!-- jboss-osgi -->
org.jboss.osgi.spi;version=1.0,
org.jboss.osgi.spi.capability;version=1.0,
org.jboss.osgi.spi.logging;version=1.0,
org.jboss.osgi.spi.management;version=1.0,
org.jboss.osgi.spi.service;version=1.0,
org.jboss.osgi.spi.testing;version=1.0,

<!-- jboss -->
org.jboss.logging,
org.jboss.virtual,
org.jboss.virtual.plugins.registry,
org.jboss.virtual.plugins.context.jar,
org.jboss.virtual.plugins.vfs.helpers,
org.jboss.virtual.protocol,
org.jboss.xb.binding;version=2.0,
org.jboss.xb.binding.sunday.unmarshalling;version=2.0,
</value>

Say good bye to modularity, if packages from services need to be defined statically as part of some non-recyclable deployer.

So how can the AS integration still be useful?
  • It is useful for folks who have plain OSGi applications that either do not interact with system services or can have static dependency on those services. i.e. you can send/receive JMS messages, but there cannot be more than one JMS service available nor can the JMS service come and go.
  • It is a neccessary starting point from which OSGi/AS integration can develop. What I describe here is the state of the current AS integration, over the course of time you should see posts explaining an ever improving OSGi/AS integration.
The AS intgration is available for
  • JBoss-5.0.1.GA
  • JBoss-5.1.0.GA
  • JBoss-5.2.0 (not yet released)
  • JBoss-6.0.0 (not yet released)
both for jdk1.5 and jdk1.6. Here is the full matrix.

There is another JBoss OSGi Runtime available, which is already covered to some extend in the Userguide. Lets have a closer look.

Standalone JBoss OSGi Runtime

The JBoss OSGi Runtime is a pure OSGi container onto which components, services and applications can be deployed.

Instead of bootstrapping the OSGi Framework from the Microcontainer, the Microcontainer Service is installed in the OSGi Framework as a bundle.

Preconfigured profiles, contain OSGi bundles that logically work together. A profile can be bootstrapped either as a standalone server or embedded in some other environment. With a startup time of less than 600ms, the runtime can be easily be bootstrapped from within plain JUnit4 test cases.

For a more detailed description and the feature set, please have a look at the userguide.

For this post lets focus on the '-c all' profile

[tdiesler@tdvaio runtime]$ bin/run.sh -c all
=========================================================================
JBossOSGi Bootstrap Environment
OSGI_HOME: /home/tdiesler/jboss-osgi-1.0.0.Beta2/runtime
JAVA: /usr/java/jdk1.6/bin/java
JAVA_OPTS: -Dprogram.name=run.sh ...
=========================================================================
... [FelixIntegration] OSGi Integration Felix - 1.0.0.Beta2
... [FelixIntegration] Installed bundle [1]: org.osgi.compendium
... [FelixIntegration] Installed bundle [2]: org.apache.felix.log
... [FelixIntegration] Installed bundle [3]: jboss-osgi-common
... [FelixIntegration] Installed bundle [4]: jboss-osgi-hotdeploy
... [OSGiBootstrap] JBossOSGi Runtime booted in 0.421sec
... [jboss-osgi-common] Installed: jboss-osgi-xml-binding [5]
... [jboss-osgi-common] Installed: jboss-osgi-microcontainer [6]
... [jboss-osgi-common] Installed: org.apache.felix.metatype [7]
... [jboss-osgi-common] Installed: jboss-osgi-jndi [8]
... [jboss-osgi-common] Installed: org.apache.felix.http.jetty [9]
... [jboss-osgi-common] Installed: org.apache.felix.configadmin [10]
... [jboss-osgi-common] Installed: jboss-osgi-jmx [11]
... [jboss-osgi-common] Installed: jboss-osgi-jaxb [12]
... [jboss-osgi-common] Installed: jboss-osgi-common-core [13]
... [jboss-osgi-common] Installed: jboss-osgi-webconsole [14]
... [jboss-osgi-common] Installed: jboss-osgi-apache-xerces [15]
... [jboss-osgi-jndi] JNDI started: JNP=localhost:1099
... [jboss-osgi-jmx] Bound to: jmx/invoker/RMIAdaptor
... [OSGiBootstrap] JBossOSGi Runtime started in 5.156sec

The OSGi Framework boots up and starts the services that are shown in the picture above. Although the startup time is considerably faster that that of the AS it should be mentioned that this is currently not optimized. OSGi comes with a lazy bundle activation policy. What you see above is 'eager' bundle activation for all. Lazy bundle activation means that bundles and their associated service can be started on demand, which should bring the startup time much closer to the boot time.

So why is this OSGi runtime useful?
  • It is useful for folks who want a "clean" OSGi environment with all the benefits that are described in the feature set
  • 3rd party bundles can be installed in that runtime and provide truly modular services similar to the ones that exist in the AS integration.
  • It is the foundation of our OSGi activities that take an already existing OSGi Framework for granted (i.e. the upcomming Blueprint implementation)

So what cannot be done with this runtime?

  • You cannot take advantage of many of the JavaEE and advanced JBoss features. EJB3, JTA, AOP, etc are not available (yet).
  • JMX and AOP annotations on MC beans do not work
  • You cannot deploy existing JBoss applications on that runtime
From the contrast of the two aproaches you see that it would be beneficial to have the benefits of both available in one runtime environment.

The possible future of JBoss OSGi

Conceptually, the Microcontainer already implements the OSGi provided functionality. Some folks even go as far as saying that the MC is a superset of OSGi. The criteria to prove the truth of that claim is well defined, MC "simply" needs to pass the OSGi core TCK.

The idea is to provide the MC with a facade that implements the OSGi core API. Our chief scientist has signed up for it, and I am exited to see what will come out of it. The resulting architecture would then look similar to this

The Microcontainer is the OSGi Framework and manages the classloading scope and lifecycle of all components deployed on it. This is the vision, the time line and details still need to be defined.

That's it for now. Next week I'll be off for a short holiday to my favourite climbing spot


In my next post I'm going to look into the OSGiRuntime abstraction and the Husky Test Harness in more detail. If you like, you can already look forward to Beta3, which should see major improvements to our Blueprint implementation - stay tuned.

May this be useful

Wednesday, June 3, 2009

JBossOSGi 1.0.0.Beta2 Released

I am happy to announce the release of JBossOSGi-1.0.0.Beta2.

You can download it here: jboss-osgi-installer-1.0.0.Beta2.jar

The release comes with improvements in the following areas
For details please have a look at the latest version of our User Guide.

Here are the change log details

Feature Request

  • [JBOSGI-70] - Expose bundle headers through JMX
Tasks
Enjoy

Thursday, April 23, 2009

OSGi Blueprint Service (RFC-124)

This post introduces the OSGi Blueprint Service (RFC-124) as it is currently drafted by the OSGi Enterprise Expert Group (EEG). I'll try to present the most relevant information in a fast and easy digestible way such that you should get a good idea of what Blueprint Service is about and why it is relevant for JBossOSGi.

Introduction

The OSGi platform provides an attractive foundation for building enterprise applications. However it lacks a rich component model for declaring components within a bundle and for instantiating, configuring, assembling and decorating such components when a bundle is started.

In 2006 SpringSource, the company behind the Spring Framework started development on a project called Spring Dynamic Modules to address the above needs. In Sep-2007 that project provided the basis for RFC-124 which is now known as "Blueprint Service".

Application Domain

The enterprise Java marketplace revolves around the Java Platform, Enterprise Edition (formerly known as J2EE) APIs. This includes APIs such as JMS, JPA, EJB, JTA, Java Servlets, JSF, JAXWS and others. The central component model of JEE is Enterprise JavaBeans (EJBs). Some core features of the enterprise programming models the market is moving to include:
  • A focus on writing business logic in “regular” Java classes that are not required to implement certain APIs or contracts in order to integrate with a container
  • Dependency injection: the ability for a component to be “given” its configuration values and references to any collaborators it needs without having to look them up. This keeps the component testable in isolation and reduces environment dependencies. Dependency injection is a special case of Inversion of Control.
  • Declarative specification of enterprise services. Transaction and security requirements for example are specified in metadata (typically XML or annotations) keeping the business logic free of such concerns. This also facilitates independent testing of components and reduces environment dependencies.
  • Aspects, or aspect-like functionality. The ability to specify in a single place behavior that augments the execution of one or more component operations.
In the JBoss Application Server all the core features from above are handled by the JBoss Microcontainer.

Problem Description

Enterprise application developers would like to be able to take advantage of the OSGi platform. The core features of enterprise programming models previously described must be retained for enterprise applications deployed in OSGi. The current OSGi specifications are lacking in the following areas with respect to this requirement:
  • There is no defined component model for the internal content of a bundle. Declarative Services only supports the declaration of components that are publicly exposed.
  • The configuration (property injection) and assembly (collaborator injection) support is very basic
  • There is no model for declarative specification of services that cut across several components (aspects or aspect-like functionality)
  • Components that interact with the OSGi runtime frequently need to depend on OSGi APIs
  • The set of types and resources visible from the context class loader is unspecified
  • Better tolerance of the dynamic aspects of the OSGi platform is required. The programming model should make it easy to deal with services that may come and go, and with collections of such services, via simple abstractions such as an injecting a constant reference to an object implementing a service interface, or to a managed collection of such objects.
Requirements (selected)
  • The solution MUST enable the instantiation and configuration of components inside a bundle based on metadata provided by the bundle developer.
  • The solution SHOULD enable the creation of components inside a bundle to be deferred until the dependencies of those components are satisfied.
  • The solution MUST provide a mechanism for a bundle component to be optionally exported as an OSGic service.
  • The solution MUST provide a mechanism for injecting a reference to an OSGi service into a bundle component. It SHOULD provide a constant service reference that the receiving component can use even if the target service backing the reference is changed at run time.
  • The solution SHOULD tolerate services in use being unregistered and support transparent rebinding to alternate services if so configured.
  • The solution SHOULD provide a rich set of instantiation, configuration, assembly, and decoration options for components
Solution

The runtime components to be created for a bundle, together with their configuration and assembly information, are specified declaratively in one or more configuration files contained within the bundle. A bundle with such information present is known as a managed bundle.

An extender bundle is responsible for observing the life cycle of such bundles. When a bundle is started, the extender creates a module context for that bundle from its blueprint by processing the configuration files and instantiating, configuring, and assembling the components specified there. When a managed bundle is stopped, the extender shuts down the module context, which causes the managed components within the context to be cleanly destroyed.

The declarative configuration for a bundle may also specify that certain of the bundle's managed components are to be exported as services in the OSGi service registry. In addition, it is possible to declare that a bundle component depends on a service or set of services obtained via the service registry, and to have those services dependency injected into the bundle component.



Module Context Life Cycle and the Extender Bundle

Module context creation and destruction

A Blueprint Service implementation must provide an extender bundle which manages the lifecycle of module contexts. This bundle is responsible for creating the module contexts for managed bundles (every ACTIVE managed bundle has one and only one associated module context).

When a managed bundle is stopped, the module context created for it is automatically destroyed. All services exported by the bundle will be unregistered


Lazy Activation


Module context instantiation is triggered when the STARTED event is issued for a given bundle, Therefore the module context for a lazily activated bundle will not be created until a class has been loaded from that bundle.

Manifest Headers for Managed Bundles

The extender recognizes a bundle as a managed bundle and will create an associated module context when the bundle is started if one or both of the following conditions is true:
  • The bundle path contains a folder OSGI-INF/blueprint with one or more files in that folder with a '.xml' extension.
  • META-INF/MANIFEST.MF contains a manifest header Bundle-Blueprint.
In the absence of the Bundle-Blueprint header the extender expects every ".xml" file in the OSGI-INF/blueprint folder to be a valid module context configuration file.

Two directives are defined by the blueprint service specification to control the manner in which module context creation occurs. These directives are applied to the Bundle-SymbolicName header.
  • blueprint.wait-for-dependencies (true|false) - controls whether or not module context creation should wait for any mandatory service dependencies to be satisfied before proceeding (the default), or proceed immediately without waiting if dependencies are not satisfied upon startup.
  • blueprint.timeout (300000) - the time to wait (in milliseconds) for mandatory dependencies to be satisfied before giving up and failing module context creation.
For example:

Bundle-SymbolicName: org.osgi.foobar;blueprint.wait-for-dependencies:=false

Bundle-SymbolicName: org.osgi.foobar;blueprint.timeout:=60000


Declaring Module Components

The basic structure of a configuration file is as follows:
<components xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"...>
<description>
Optional description for the blueprint defined in this file.
</description>
<component id="..." class="...">
<!-- collaborators and configuration for this component go here -->
</component>
<component id="..." class="...">
<!-- collaborators and configuration for this component go here -->
</component>
<!-- more component definitions go here... -->
</components>
Naming Components

Every component has at most one id. Component ids must be unique within a module.

Implicit Component Definitions

A module context contains a number of implicitly defined components with well-known names.
  • ModuleContext - provides access to the component objects within the module context
  • Bundle and BundleContext - represents the bundle and its contextwith which the module context is associated
  • ConversionService - provides access to the type conversions that are defined for the module context
Instantiating Components

Object instantiation is supported in the following ways:
  • Using a constructor
  • Using a static factory method
  • Using an instance factory method
Dependencies

A typical module is made up of components that work (or collaborate) together. The basic principle behind Dependency Injection (DI) is that objects define their dependencies only through constructor arguments, arguments to a factory method, or properties which are set on the object instance after it has been constructed or returned from a factory method.

Dependency Injection is supported in the following ways:
  • Constructor Injection
  • Setter Injection
Type Conversion

String values in module context configuration files must be converted to the type expected by an injection target. The module context container supports a number of type conversions by default, and provides an extension mechanism for configuring additional type converters.

Lazily instantiated components

By default all singleton components in a module context will be pre-instantiated at startup. A lazily initialized component is not created at startup and will instead be created when it is first requested.

Component Scopes

Components can be defined to be deployed in one of a number of scopes, specified using the scope attribute:
  • Singleton - scopes a single component definition to a single object instance per module context
  • Prototype - scopes a single component definition to any number of object instances
  • Bundle - scopes a single component definition to a single object per requesting client bundle
Lifecycle

Specifying an init-method for a component enables a component to perform initialization work once all the necessary properties on a component have been set by the container. Specifying a destroy-method enables a component to get a callback when the module context containing it is destroyed.

Interacting with the Service Registry

The osgi namespace provides elements that can be used to export managed components as OSGi services, to define references to services obtained via the registry.

Exporting a managed component to the Service Registry

The service element is used to define a component representing an exported OSGi service. At a minimum you must specify the managed component to be exported, and the service interface that the service advertises.

For example

<service ref="comp" interface="com.xyz.MessageService"/>

Controlling the set of advertised service interfaces

The simplest mechanism, shown above, is to use the interface attribute to specify a fully-qualified interface name. To register a service under multiple interfaces the nested interfaces element can be used in place of the interface attribute.
<service ref="componentToBeExported">
<interfaces>
<value>com.xyz.MessageService</value>
<value>com.xyz.MarkerInterface</value>
</interfaces>
</service>
Using the auto-export attribute you can avoid the need to explicitly declare the service interfaces at all by analyzing the object class hierarchy and its interfaces. The auto-export attribute can have one of four values:
  • disabled : the default value; no auto-detected of service interfaces
  • interfaces : all of the Java interface types implemented by the component
  • class-hierarchy : component's implementation type and super-types
  • all-classes : component's implementation type and super-types plus all interfaces implemented by the component.
Controlling the set of advertised properties

Additional service properties can be specified using the nested service-properties element.
<service ref="componentToBeExported" interface="com.xyz.MyServiceInterface">
<service-properties>
<entry key="myOtherKey" value="aStringValue"/>
<entry key="aThirdKey" value-ref="componentToExposeAsProperty"/>
<service-properties>
</service>
The depends-on attribute

The depends-on attribute can be used to provide a comma-delimited list of component names for components that must be instantiated and configured before the service is published to the registry.

Dealing with service dynamics

The component defined by a reference element is unchanged throughout the lifetime of the module context (the object reference remains constant). However, the OSGi service that backs the reference may come and go at any time.

When the service backing a reference component goes away, an attempt is made to replace the backing service with another service matching the reference criteria. If no matching service is available, then the reference is said to be unsatisfied.

When an operation is invoked on an unsatisfied reference component, the invocation blocks until either the reference becomes satisfied or a timeout expires.

Mandatory dependencies

An exported service may depend, either directly or indirectly, on other services in order to perform its function. If one of these services is considered a mandatory dependency and the dependency can no longer be satisfied (because the backing service has gone away and there is no suitable replacement
available) then the exported service that depends on it will be automatically unregistered from the service registry.

Service Listeners

Applications that need to be aware of when a service backing a reference component is bound and unbound, or when a member is added to or removed from a collection, can register one or more listeners using the nested listener element.

For example:
<reference id="someService" interface="com.xyz.MessageService">
<listener bind-method="onBind" unbind-method="onUnbind">
<component class="MyCustomListener"/>
</listener>
</reference>
Namespace Extension Mechanism

Third parties may contribute additional namespaces containing elements and attributes used to configure the components for a module context.

In order to be able to interpret elements and attributes declared in third party namespaces, a namespace handler must be registered that the container can delegate to.

Here an example of a hypothetical "cache" namespace:
<cache:lru-cache id="myCache"/>
<component id="fooService" class="FooServiceImpl" cache:cache-return-values="true">
<cache:exclude>
<cache:operation name="getVolatile"/>
</cache:exclude>
<property name="myProp" value="12"/>
</component>
Credits

Adrian Colyer from SpringSource is the author of the Blueprint Service specification.

Non intrusive OSGi Bundle Testing

For JBossOSGi I was looking for ways to test bundles that are deployed to a remote instance of the JBossOSGi Runtime. I wanted the solution to also work with an OSGi Framework that is bootstrapped from within a JUnit test case.

The basic problem is of course that you cannot access the artefacts that you deploy in a bundle directly from your test case, because they are loaded from different classloaders.



Most solutions to the problem somehow bring the test case into the OSGi Framework such that it can access the test bundle. They run the test and finally communicate the results back to the test framework. This approach is well documented in Chapter 11 of the Spring Dynamic Modules Reference Guide

Lets have a look at the specific JBossOSGi test requirements
  • OSGi Framework agnostic
  • non-intrusive to the test bundle
  • works for embedded and remote test scenarios
  • simple and fast to implement
To achieve that it seemed natural to leverage what OSGi provides natively in terms of reporting, which would be the Log Service from the OSGi compendium specification. The approach would work like this
  1. Test Case registers a LogListener with the LogReaderService
  2. Test bundle logs messages to the LogService
  3. Test Case verifies the order and content of the received log messages
The JBossOSGi SPI provides a special LogListener in form of the LogEntryCache to do the log entry caching, filtering and lookup.

But let's talk a little detour into the Log Service from the OSGi compendium specification.



LogService – The service interface that allows a bundle to log information, including a message, a level, an exception, a ServiceReference object, and a Bundle object.

LogEntry - An interface that allows access to a log entry in the log. It includes all the information that can be logged through the Log Service and a time stamp.

LogReaderService - A service interface that allows access to a list of recent LogEntry objects, and allows the registration of a LogListener object that receives LogEntry objects as they are created.

LogListener - The interface for the listener to LogEntry objects. Must be registered with the Log Reader Service.

First a test bundle needs to obtain an instance of the LogService. Here is a bad way of doing this
String sName = LogService.class.getName();
ServiceReference sRef = ctx.getServiceReference(sName);
LogService log = sysContext.getService(sRef);
The code above has two issues
  1. It assumes that there is LogService registered
  2. It does not detect when the LogService disappears
Here is a better way of obtaining the LogService
String sName = LogService.class.getName();
LogService log = new SystemLogService(context);
tracker = new ServiceTracker(context, sName, null)
{
public Object addingService(ServiceReference reference)
{
log = (LogService)super.addingService(reference);
return log;
}
public void removedService(ServiceReference reference, Object service)
{
super.removedService(reference, service);
log = new SystemLogService(context);
}
};
tracker.open();
The code above initializes the log instance with the SystemLogService that is part of the jboss-osgi-common.jar bundle. The tracker overrides the log instance when an actual LogService gets registered. The tracker restores the SystemLogService, in case the LogService disappears again.

This LogService tracking code is so common that the jboss-osgi-common.jar bundle already contains a tracker which does all of the above. Hence, the best way to obtaining the LogService with JBossOSGi ist
LogService log = new LogServiceTracker(context);
Now that the test bundle actually has an instance of the LogService it can start logging messages to that service. These messages are seen by the LogReaderService that the test case can register a LogListener with.

In the test case you would create a new LogEntryCache and associate one or more LogEntryFilter objects with it.
LogEntryCache logEntryCache = new LogEntryCache();
LogEntryFilter filter = new LogEntryFilter("example-log(.*)", 0, null);
logEntryCache.addFilter(filter);
The LogEntryCache is then added to the LogReaderService using a ServiceTracker similar to the one above. Because the filters are 'or' combined the cache stores log enties that pass at least one filter in the list. Each filter has three filter criteria
  1. A regular expression that matches a Bundle-SymbolicName
  2. A minimum LogLevel, whereas 0 indicates any LogLevel
  3. A regular expression that matches the log message
A test case can now verify the cached log messages like this
List entries = logEntryCache.getLog();
assertEquals("Number of entries", 1, entries.size());
assertEquals("[ServiceA] new Service", entries.get(0).getMessage());
In the remote test scenario it works essentially in the same way, only that a RemoteLogListener sends the LogEnties to a RemoteLogReaderService. The local test case registers it's LogEntryCache with the RemoteLogReaderService.


The actual communication is done with the JBoss Remoting socket transport. Both, the RemoteLogListener and the RemoteLogReaderService are part of the jboss-osgi-remotelog.jar bundle. That bundle needs to be installed with matching properties in the local and the remote OSGi Framework.
  • org.jboss.osgi.service.remote.log.sender - Enable the server side LogListener
  • org.jboss.osgi.service.remote.log.reader - Enable the client side LogReaderService
  • org.jboss.osgi.service.remote.log.host - The remote host that log messages are sent to
  • org.jboss.osgi.service.remote.log.port - The remote port that log messages are sent to
You may also want to have a look at Chapter 5.2 Remote Log Service of the JBossOSGi User Guide.

In my next post I'm going to look into the Blueprint Service (RFC-124) specification, which provides a rich component model for declaring components within a bundle and for instantiating, configuring, assembling and decorating such components - stay tuned.

May this be useful

Wednesday, April 22, 2009

JBossOSGi 1.0.0.Beta1 Released

I am happy to announce the release of JBossOSGi-1.0.0.Beta1.

You can download it here: jboss-osgi-installer-1.0.0.Beta1.jar

The release comes with improvements in the following areas
  • Added Equinox and Knopflerfish integration
  • Improved test support for remote and embedded scenarios
  • A set of installer provided OSGi examples
  • A bundle for remote and local log message filtering
For details please have a look at the latest version of our User Guide.

Here are the change log details

Tasks

[JBOSGI-28] - Setup OSGi Framework TCK
[JBOSGI-31] - Integration layer for Equinox
[JBOSGI-32] - Integration layer for Knopflerfish
[JBOSGI-59] - Provide initial Examples
[JBOSGI-63] - Update to Felix HTTP Service (Jetty) 1.0.0
[JBOSGI-64] - Update to Felix Log Service 1.0.0
[JBOSGI-65] - Update to Felix 1.6.0

Bugs

[JBOSGI-36] - Bundle classes leak into system classloader
[JBOSGI-37] - Prevent creation of deployment unit for nested jars
[JBOSGI-40] - Cannot run embedded tests with SecurityManager

Enjoy

Monday, March 30, 2009

JBossOSGi - First Release

I am happy to announce the release of JBossOSGi-1.0.0.Alpha3.

You can download it here: jboss-osgi-installer-1.0.0.Alpha3.jar

JBossOSGi-1.0.0.Alpha3 is our first functional release that comes with:

  • Apache Felix integration
  • A specialized JBossOSGi Runtime
  • Integrated Hudson QA
  • IzPack based Installer
  • Bundle hot deployment
  • Management Console
  • Docbook Guides
  • HttpService
  • LogService

You may also what to have a look at the JBossOSGi Diary blog posts

  1. Getting Started
  2. Service Provider Interface
  3. Provided Services
Here are the change log details

Tasks
  • [JBOSGI-29] - Provide Initial Framework SPI
  • [JBOSGI-30] - Integration layer for Apache Felix
  • [JBOSGI-35] - Setup JBoss OSGi download area
  • [JBOSGI-38] - Investigate bundle install/start behaviour with random deployment order
  • [JBOSGI-41] - Verify persistent file storage
  • [JBOSGI-42] - Provide IzPack based Installer
  • [JBOSGI-43] - Hudson QA as integral part of each project release
  • [JBOSGI-44] - Provide bundle hot-deployment on jboss
  • [JBOSGI-45] - Provide minimal JBossOSGi Runtime
  • [JBOSGI-46] - Integrate 3rd party HttpService
  • [JBOSGI-47] - Delegate 3rd party framework logging to jboss logging
  • [JBOSGI-48] - Integrate 3rd party LoggingService
  • [JBOSGI-49] - Integrate 3rd party Management Console
  • [JBOSGI-50] - Provide a docbook guides
  • [JBOSGI-51] - Provide a management view (JMX) on framework and bundles

Enjoy