JBoss Community Archive (Read Only)

JBoss OSGi

Provided Examples

Build and Run the Examples

JBoss OSGi comes with a number of examples that demonstrate supported functionality and show best practices. All examples are part of the binary distribution and tightly integrated in our Maven Build Process.

The examples can be either run against an embedded OSGi framework or against WildFly. Here is how you build and run the standalone framework tests.

[tdiesler@localhost example]$ mvn clean test
 
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.jboss.test.osgi.example.blueprint.BlueprintTestCase
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.225 sec
...

Tests run: 22, Failures: 0, Errors: 0, Skipped: 1

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.846s
[INFO] Finished at: Fri Jun 28 10:24:25 CEST 2013
[INFO] Final Memory: 25M/202M
[INFO] ------------------------------------------------------------------------

To run the examples against WildFly, you need to provide the target container that the runtime should connect to. This can be done with the target.container system property.

    mvn -Dtarget.container=wildfly800 test

Examples for Standalone & Remote WildFly

This section covers example tests that run both in the standalone and remote WildFly runtimes.

Blueprint Container

The BlueprintTestCase shows how a number of components can be wired together and registered as OSGi service through the Blueprint Container Service.

The example uses this simple blueprint descriptor

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" ...>
  
  <bean id="beanA" class="org.jboss.test.osgi.example.blueprint.bundle.BeanA">
    <property name="mbeanServer" ref="mbeanService"/>
  </bean>
  
  <service id="serviceA" ref="beanA" interface="org.jboss.test.osgi.example.blueprint.bundle.ServiceA">
  </service>
  
  <service id="serviceB" interface="org.jboss.test.osgi.example.blueprint.bundle.ServiceB">
    <bean class="org.jboss.test.osgi.example.blueprint.bundle.BeanB">
       <property name="beanA" ref="beanA"/>
    </bean>
  </service>
  
  <reference id="mbeanService" interface="javax.management.MBeanServer"/>

</blueprint>

The Blueprint Container registers two services ServiceA and ServiceB. ServiceA is backed up by BeanA, ServiceB is backed up by the anonymous BeanB. BeanA is injected into BeanB and the MBeanServer gets injected into BeanA. Both beans are plain POJOs. There is no BundleActivator neccessary to register the services.

The example test verifies the correct wiring like this

@Test
public void testServiceA() throws Exception
{
  ServiceReference<ServiceA> srefA = context.getServiceReference(ServiceA.class);
  assertNotNull("ServiceA not null", srefA);
  
  ServiceA serviceA = context.getService(srefA);
  MBeanServer mbeanServer = serviceA.getMbeanServer();
  assertNotNull("MBeanServer not null", mbeanServer);

  ServiceReference<ServiceB> srefB = context.getServiceReference(ServiceB.class);
  assertNotNull("ServiceB not null", srefB);
  
  ServiceB serviceB = context.getService(sref);
  BeanA beanA = serviceB.getBeanA();
  assertNotNull("BeanA not null", beanA);
}

Configuration Admin

The ConfigurationAdminTestCase shows how an OSGi ManagedService can be configured through the ConfigurationAdmin service.

public void testManagedService() throws Exception {

   // Get the {@link Configuration} for the given PID
   Configuration config = configAdmin.getConfiguration(ConfiguredService.SERVICE_PID);
   assertNotNull("Config not null", config);

   Dictionary<String, String> configProps = new Hashtable<String, String>();
   configProps.put("foo", "bar");
   config.update(configProps);

   // Register a {@link ManagedService}
   Dictionary<String, String> serviceProps = new Hashtable<String, String>();
   serviceProps.put(Constants.SERVICE_PID, ConfiguredService.SERVICE_PID);
   bundlecontext.registerService(new String[] { ConfiguredService.class.getName(), 
      ManagedService.class.getName() }, new ConfiguredService(), serviceProps);

   // Wait a little for the update event
   if (latch.await(5, TimeUnit.SECONDS) == false)
      throw new TimeoutException();

   // Verify service property
   ServiceReference sref = bundlecontext.getServiceReference(ConfiguredService.class.getName());
   ConfiguredService service = (ConfiguredService) bundlecontext.getService(sref);
   assertEquals("bar", service.getValue("foo"));

   config.delete();
}

Declarative Services

The DeclarativeServicesTestCase shows how a service can be made available through a Declarative Services descriptor.

<component name="sample.component" immediate="true">
  <implementation class="org.jboss.test.osgi.example.ds.SampleComparator" />
  <property name="service.description" value="Sample Comparator Service" />
  <property name="service.vendor" value="Apache Software Foundation" />
  <service>
    <provide interface="java.util.Comparator" />
  </service>
</component>

The test then verifies that the service becomes available

public void testImmediateService() throws Exception {

  // Track the service provided by the test bundle
  final CountDownLatch latch = new CountDownLatch(1);
  ServiceTracker tracker = new ServiceTracker(context, Comparator.class.getName(), null) {
     public Object addingService(ServiceReference reference) {
         Comparator<Object> service = (Comparator<Object>) super.addingService(reference);
         latch.countDown();
         return service;
     }
  };
  tracker.open();

  // Wait for the service to become available
  if (latch.await(2, TimeUnit.SECONDS) == false)
    throw new TimeoutException("Timeout tracking Comparator service");
}

Event Admin

The EventAdminTestCase uses the EventAdmin service to send/receive events.

public void testEventHandler() throws Exception
{
  TestEventHandler eventHandler = new TestEventHandler();
  
  // Register the EventHandler
  Dictionary param = new Hashtable();
  param.put(EventConstants.EVENT_TOPIC, new String[Introduction] { TOPIC });
  context.registerService(EventHandler.class.getName(), eventHandler, param);

  // Send event through the the EventAdmin
  EventAdmin eventAdmin = EventAdminSupport.provideEventAdmin(context, bundle);
  eventAdmin.sendEvent(new Event(TOPIC, null));
  
  // Verify received event
  assertEquals("Event received", 1, eventHandler.received.size());
  assertEquals(TOPIC, eventHandler.received.get(0).getTopic());
}

JNDI Service

The NamingStandaloneTestCase gets the JNDIContextManager service and verifies JNDI access.

ServiceReference<JNDIContextManager> sref = context.getServiceReference(JNDIContextManager.class);
JNDIContextManager contextManager = context.getService(sref);
Context initialContext = contextManager.newInitialContext();
BundleContext context = (BundleContext) initialContext.lookup("osgi:framework/bundleContext");
Assert.assertEquals(bundle.getBundleContext(), context);

JMX Service

The MBeanServerTestCase tracks the MBeanServer service and registers a pojo with JMX. It then verifies the JMX access.

public class MBeanActivator implements BundleActivator
{
   public void start(BundleContext context)
   {
      ServiceTracker tracker = new ServiceTracker(context, MBeanServer.class.getName(), null)
      {
         public Object addingService(ServiceReference reference)
         {
            MBeanServer mbeanServer = (MBeanServer)super.addingService(reference);
            registerMBean(mbeanServer);
            return mbeanServer;
         }

         @Override
         public void removedService(ServiceReference reference, Object service)
         {
            unregisterMBean((MBeanServer)service);
            super.removedService(reference, service);
         }
      };
      tracker.open();
   }

   public void stop(BundleContext context)
   {
      ServiceReference sref = context.getServiceReference(MBeanServer.class.getName());
      if (sref != null)
      {
         MBeanServer mbeanServer = (MBeanServer)context.getService(sref);
         unregisterMBean(mbeanServer);
      }
   }
   ...
}
public void testMBeanAccess() throws Exception
{
   // Provide MBeanServer support
   MBeanServer server = ManagementSupport.provideMBeanServer(context, bundle);

   // Start the test bundle
   bundle.start();

   ObjectName oname = ObjectName.getInstance(FooMBean.MBEAN_NAME);
   FooMBean foo = ManagementSupport.getMBeanProxy(server, oname, FooMBean.class);
   assertEquals("hello", foo.echo("hello"));
}

The BundleStateTestCase uses JMX to control the bundle state through the BundleStateMBean.

public void testBundleStateMBean() throws Exception
{
   MBeanServer server = ManagementSupport.provideMBeanServer(context, bundle);

   ObjectName oname = ObjectName.getInstance(BundleStateMBean.OBJECTNAME);
   BundleStateMBean bundleState =  ManagementSupport.getMBeanProxy(server, oname, BundleStateMBean.class);
   assertNotNull("BundleStateMBean not null", bundleState);

   TabularData bundleData = bundleState.listBundles();
   assertNotNull("TabularData not null", bundleData);
   assertFalse("TabularData not empty", bundleData.isEmpty());
}

Examples for WildFly Integration

This section covers example tests that only run both in the remote WildFly integration.

CDI Integration

The ManagedBeansTestCase deploys and EAR file that contains a WAR and three bundles. The first bundle tracks payment service providers

    private BundleContext context;

    @Resource
    public void setContext(BundleContext context) {
        this.context = context;
    }

    private List<PaymentProvider> providers = new ArrayList<PaymentProvider>();

    @PostConstruct
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public void start() {
        ServiceTracker tracker = new ServiceTracker(context, PaymentProvider.class.getName(), null) {

            @Override
            public Object addingService(ServiceReference reference) {
                PaymentProvider service = (PaymentProvider) super.addingService(reference);
                providers.add(service);
                return service;
            }

            @Override
            public void removedService(ServiceReference reference, Object service) {
                providers.remove(service);
                super.removedService(reference, service);
            }
        };
        tracker.open();
    }

The other two bundles each provide an OSGi payment service, which gets injected into the webapp via CDI. The advantage of this approach is that we can construct modular web applications from independent components (i.e. bundles) which have lifecyle. We can therefore easily add/remove/start/stop/update payment service providers.

EAR Deployments

The EnterpriseArchiveTestCase shows that OSGi bundles can be deployed as part on an EAR. It is guaranteed the contained bundles all get 'installed' before they get 'resolved' and 'started'. With a large set of individual bundle deployments that have complex interdependencies it would be hard to deploy the bundles in the correct order. EAR deployments fix that ordering issue.

EJB3 Integration

The StatelessBeanTestCase verifies that an EJB can be deployed as OSGi bundle. The stateless session bean then accesses on OSGi services

@Stateless
@LocalBean
public class SimpleStatelessSessionBean implements Echo {

    @Resource
    BundleContext context;

    public String echo(String message) {
        if (context == null) 
           throw new IllegalStateException("BundleContext not injected");

        if (BUNDLE_SYMBOLICNAME.equals(message)) {
            Bundle bundle = getTargetBundle();
            return bundle.getSymbolicName();
        }
        ...
    }
}

HttpService

The HttpServiceTestCase deploys a Service that registeres a servlet and a resource with the HttpService.

ServiceTracker tracker = new ServiceTracker(context, HttpService.class.getName(), null);
tracker.open();

HttpService httpService = (HttpService)tracker.getService();
if (httpService == null)
   throw new IllegalStateException("HttpService not registered");

Properties initParams = new Properties();
initParams.setProperty("initProp", "SomeValue");
httpService.registerServlet("/servlet", new EndpointServlet(context), initParams, null);
httpService.registerResources("/file", "/res", null);

The test then verifies that the registered servlet context and the registered resource can be accessed.

JAXB Integration

The XMLBindingTestCase verifies that an OSGi bundle can use the JAXB integration that is available in WildFly

        builder.addImportPackages("javax.xml.bind", "javax.xml.bind.annotation");
        builder.addImportPackages("javax.xml.datatype", "javax.xml.namespace");

        JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class...);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        URL resURL = bundle.getResource("booking.xml");
        JAXBElement<CourseBooking> rootElement = unmarshaller.unmarshal(resURL.openStream());
        assertNotNull("root element not null", rootElement);

JPA Integration

The PersistenceTestCase verifies that an OSGi bundle can use the Hibernate JPA integration in WildFly

        EntityManagerFactory emf = null;
        try {
            ServiceReference<EntityManagerFactory> sref = context.getServiceReference(EntityManagerFactory.class);
            emf = context.getService(sref);

            Employee emp = new Employee();
            emp.setId(100);
            emp.setAddress("Sesame Street");
            emp.setName("Kermit");

            EntityManager em = emf.createEntityManager();
            em.persist(emp);

            emp = em.find(Employee.class, 100);
            Assert.assertNotNull("Employee not null", emp);

            em.remove(emp);

        } finally {
            if (emf != null) {
                emf.close();
            }
        }

JTA Service

The TransactionTestCase gets the UserTransaction service and registers a transactional user object (i.e. one that implements Synchronization) with the TransactionManager service. It then verifies that modifications on the user object are transactional.

This functionality is only available in the context of AS7.

Transactional txObj = new Transactional();

ServiceReference userTxRef = context.getServiceReference(UserTransaction.class.getName());
assertNotNull("UserTransaction service not null", userTxRef);

UserTransaction userTx = (UserTransaction)context.getService(userTxRef);
assertNotNull("UserTransaction not null", userTx);

userTx.begin();
try
{
   ServiceReference tmRef = context.getServiceReference(TransactionManager.class.getName());
   assertNotNull("TransactionManager service not null", tmRef);
   
   TransactionManager tm = (TransactionManager)context.getService(tmRef);
   assertNotNull("TransactionManager not null", tm);
   
   Transaction tx = tm.getTransaction();
   assertNotNull("Transaction not null", tx);
   
   tx.registerSynchronization(txObj);
   
   txObj.setMessage("Donate $1.000.000");
   assertNull("Uncommited message null", txObj.getMessage());
   
   userTx.commit();
}
catch (Exception e)
{
   userTx.setRollbackOnly();
}

assertEquals("Donate $1.000.000", txObj.getMessage());
class Transactional implements Synchronization
{
  public void afterCompletion(int status)
  {
     if (status == Status.STATUS_COMMITTED)
        message = volatileMessage;
  }
  
  ...      
}

Lifecycle Interceptor

The LifecycleInterceptorTestCase deployes a bundle that contains some metadata and an interceptor bundle that processes the metadata and registeres an http endpoint from it. The idea is that the bundle does not process its own metadata. Instead this work is delegated to some specialized metadata processor (i.e. the interceptor).

Each interceptor is itself registered as a service. This is the well known Whiteboard Pattern.

public class InterceptorActivator implements BundleActivator
{
   public void start(BundleContext context)
   {
      LifecycleInterceptor publisher = new PublisherInterceptor();
      LifecycleInterceptor parser = new ParserInterceptor();
      
      // Add the interceptors, the order of which is handles by the service
      context.registerService(LifecycleInterceptor.class.getName(), publisher, null);
      context.registerService(LifecycleInterceptor.class.getName(), parser, null);
   }
}
public class ParserInterceptor extends AbstractLifecycleInterceptor
{
   ParserInterceptor()
   {
      // Add the provided output
      addOutput(HttpMetadata.class);
   }

   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)
      {
          VirtualFile root = context.getRoot();
          VirtualFile propsFile = root.getChild("/http-metadata.properties");
          if (propsFile != null)
          {
             log.info("Create and attach HttpMetadata");
             metadata = createHttpMetadata(propsFile);
             context.addAttachment(HttpMetadata.class, metadata);
          }
      }
   }
   ...
}
public class PublisherInterceptor extends AbstractLifecycleInterceptor
{
   PublisherInterceptor()
   {
      // Add the required input
      addInput(HttpMetadata.class);
   }

   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();

         // 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);
      }

      // 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");
      }
   }
}

Resource Injection

The ResourceInjectionTestCase verifies that resources can be injected in OSGi bundle activators.

public class ResourceInjectionActivator implements BundleActivator {

    @Resource(name = "java:jboss/datasources/ExampleDS")
    public DataSource ds;

    public void start(BundleContext context) throws Exception {
        String productName = ds.getConnection().getMetaData().getDatabaseProductName();
        ...
    }
}

REST Integration

The RestEndpointTestCase verifies that OSGi bundles can provide REST endpoints. REST endpoints can therefore be part of larger modular applications and have lifecycle - they can be started/stopped/updated, etc. REST endpoints can access OSGi services.

@Path("/rest")
@Consumes({ "application/json" })
@Produces({ "application/json" })
public class SimpleRestEndpoint {

    private static final Logger log = Logger.getLogger(SimpleRestEndpoint.class);

    @Resource
    private BundleContext context;

    @GET
    @Path("/echo/{message}")
    public String echo(@PathParam("message") String message) {
        ServiceReference<Echo> sref = context.getServiceReference(Echo.class);
        return context.getService(sref).echo(message);
    }
}

Web Services Integration

The WebServiceEndpointTestCase verifies that OSGi bundles can provide WebService endpoints. WebService endpoints can therefore be part of larger modular applications and have lifecycle - they can be started/stopped/updated, etc. WebService endpoints can access OSGi services.

Web Application

The WebAppTestCase deploys an OSGi Web Application Bundle (WAB). Similar to HTTP Service Example it registers a servlet and resources with the WebApp container. This is done through a standard web.xml descriptor.

<web-app xmlns="http://java.sun.com/xml/ns/javaee" ... version="2.5">

  <display-name>WebApp Sample</display-name>

  <servlet>
    <servlet-name>servlet</servlet-name>
    <servlet-class>org.jboss.test.osgi.example.webapp.bundle.EndpointServlet</servlet-class>
    <init-param>
      <param-name>initProp</param-name>
      <param-value>SomeValue</param-value>
    </init-param>
  </servlet>

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

</web-app>

The associated OSGi manifest looks like this.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: example-webapp
Bundle-ClassPath: .,WEB-INF/classes
Web-ContextPath: example-webapp
Import-Package: javax.servlet,javax.servlet.http,...

The test verifies that we can access the servlet and some resources.

public void testServletAccess() throws Exception
{
   // Provide WebApp support
   WebAppSupport.provideWebappSupport(context, bundle);
        
   // Start the test bundle
   bundle.start();
        
   String line = getHttpResponse("/example-webapp/servlet?test=plain", 5000);
   assertEquals("Hello from Servlet", line);
}

XML Parser Services

The XML parser test cases get a DocumentBuilderFactory/SAXParserFactory respectivly and unmarshalls an XML document using that parser.

DocumentBuilderFactory factory = XMLParserSupport.provideDocumentBuilderFactory(context, bundle);
factory.setValidating(false);

DocumentBuilder domBuilder = factory.newDocumentBuilder();
URL resURL = context.getBundle().getResource("example-xml-parser.xml");
Document dom = domBuilder.parse(resURL.openStream());
assertNotNull("Document not null", dom);
SAXParserFactory factory = XMLParserSupport.provideSAXParserFactory(context, bundle);
factory.setValidating(false);

SAXParser saxParser = factory.newSAXParser();
URL resURL = context.getBundle().getResource("example-xml-parser.xml");

SAXHandler saxHandler = new SAXHandler();
saxParser.parse(resURL.openStream(), saxHandler);
assertEquals("content", saxHandler.getContent());
JBoss.org Content Archive (Read Only), exported from JBoss Community Documentation Editor at 2020-03-11 11:34:49 UTC, last content change 2013-07-01 11:57:01 UTC.