OSGi – Comparing service dependency management with Blueprint (part 2)

Previous Posts:

Blueprint Overview:

  • Dependency injection framework for OSGi
  • OSGi R4.2
  • XML based configuration
  • Annotation based configuration in prototype stage (as of Jul 2013)
  • Apache Aries – implementation of Blueprint (on 1.0.0 with some visible support but not heavy)
    • 15th December 2010 Aries graduates from the incubator
    • September 2010 0.2-incubating release available, including the results of compliance tests.
    • May 2010 0.1-incubating release available

Summary of findings:

  • CON: It was much harder to get up and running with Blueprint: large number of bundles and bundle dependency issues to resolve.
  • PRO: OSGi awareness is limited to an XML config file (OSGI-INF/blueprint/config.xml).  No OSGi dependencies were needed by the Date Service API or Date Service Impl.  I added an OSGi dependency to the HelloWorldFilter in order to use the HttpService from felix which was needed to register the servlet and filter.
  • CON: Could not _easily_ get the example to work.  The servlet registered correctly to the HttpService (wired in by Blueprint).  But the DateService gave a proxy exception.  Something is still not quite right with the configuration/wiring of the DateService to the HelloWorldFilter.

Setup:

  1. Follow common setup steps listed in Part 1. Recommendation is to use a separate installation of Felix for each one of these examples to easily flip between the different wiring mechanisms.
  2. Download the Apache Aries Blueprint bundles from: http://aries.apache.org/downloads/currentrelease.html. Versions listed are the versions used at time of post.  I copied all bundle downloads to my ${FELIX_HOME}/bundle directory.  This step makes me cringe.  There’s gotta be a better way (PAX?  Using maven dependencies to pull down the artifacts and copy to the felix home?)
    • org.apache.aries.util (1.0.0) jar
    • slf4j-simple (1.7.5)
    • slf4j-api (1.7.5)
    • log4j-over-slf4j (1.7.5) jar
    • org.apache.aries.proxy (1.0.0) jar
    • org.osgi.compendium-4.2.0.jar
    • org.apache.aries.blueprint (1.1.0) jar
  3. Install and start the bundles downloaded in step 2 (slf4j-simple will only need an install since it is a bundle fragment).  Order is very important, and I’ve listed these bundles in install and start order (top to bottom)
  4. Your bundle list should look like the following:
    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (4.2.1)
        1|Active     |    1|Apache Felix Bundle Repository (1.6.6)
        2|Active     |    1|Apache Felix Gogo Command (0.12.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.10.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.10.0)
        5|Active     |    1|Apache Felix Http Jetty (2.2.0)
        6|Active     |    1|Apache Aries Blueprint Bundle (1.1.0)
        7|Active     |    1|Apache Aries Proxy Bundle (1.0.0)
        8|Active     |    1|Apache Aries Util (1.0.0)
       13|Resolved   |    1|slf4j-simple (1.7.5)
       14|Active     |    1|log4j-over-slf4j (1.7.5)
       15|Active     |    1|slf4j-api (1.7.5)
       18|Active     |    1|osgi.cmpn (4.2.0.200908310645)
  5. Install and start the 3 bundles from your osgi-evaluation/examples/wiring/*/target/*jar
  6. Test to verify your servlet (with a response header of WIZARD) and your filter (with a response body of Hello World) and your Date Service (wired into your filter to add a formatted date to your response body) are wired together correctly to service your request.  At the time of this post, my filter was throwing an exception and not calling the DateService formattedDate() function correctly.
[~/felix] : curl localhost:8080 -v
* About to connect() to localhost port 8080 (#0)
*   Trying ::1...
* connected
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8x zlib/1.2.5
> Host: localhost:8080
> Accept: */*
> 
< HTTP/1.1 500 object is not an instance of declaring class
< WIZARD: JAWSOME
< Content-Type: text/html; charset=iso-8859-1
< Cache-Control: must-revalidate,no-cache,no-store
< Content-Length: 3846
< Server: Jetty(6.1.x)
< 
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<title>Error 500 object is not an instance of declaring class</title>
</head>
<body><h2>HTTP ERROR 500</h2>
<p>Problem accessing /. Reason:
<pre>    object is not an instance of declaring class</pre></p><h3>Caused by:</h3><pre>java.lang.IllegalArgumentException: object is not an instance of declaring class
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.aries.proxy.impl.ProxyHandler$1.invoke(ProxyHandler.java:54)
    at org.apache.aries.proxy.impl.ProxyHandler.invoke(ProxyHandler.java:119)
    at com.sun.proxy.$Proxy5.getFormattedDate(Unknown Source)
    at org.osgiexample.filters.helloworld.HelloWorldFilter.doFilter(HelloWorldFilter.java:42)
    at org.apache.felix.http.base.internal.handler.FilterHandler.doHandle(FilterHandler.java:88)
    at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:76)
    at org.apache.felix.http.base.internal.dispatch.InvocationFilterChain.doFilter(InvocationFilterChain.java:47)
    at org.apache.felix.http.base.internal.dispatch.HttpFilterChain.doFilter(HttpFilterChain.java:33)
    at org.apache.felix.http.base.internal.dispatch.FilterPipeline.dispatch(FilterPipeline.java:48)
    at org.apache.felix.http.base.internal.dispatch.Dispatcher.dispatch(Dispatcher.java:39)
    at org.apache.felix.http.base.internal.DispatcherServlet.service(DispatcherServlet.java:67)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:390)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:926)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
</pre>
<hr /><i><small>Powered by Jetty://</small></i><br/>

Next Post:

  • Coming soon: OSGi – Comparing service dependency management with iPojo (part 3)

OSGi – Service dependency management with BundleActivator, Blueprint, Declarative Services, and iPojo (part 1)

Goals:

There are many good tutorials and wiki / blog postings on OSGi.  What I’m exploring with this post is to become more familiar with the different strategies for wiring up bundles and services within an OSGi container.

  1. Prototype a servlet filter in the Apache Felix OSGi container
    • Add a response header of “JAWSOME” with a value of “WIZARD”
    • Add a response body of “Hello World: today is ${formattedDate}”
    • Obtain the value of ${formattedDate} from an OSGi managed DateService
    • Update the DateService implementation to change the formattedDate string
  2. Evaluate service dependency management with BundleActivator, Blueprint, iPojo, Declarative Services

Setup for all Examples:

  1. Clone the git repository: https://github.com/CoderLisa/osgi-evaluation.git
  2. Build the examples in the git repository (maven and JDK are required)
  3. Download and install the latest Apache Felix Framework distribution (version 4.2.1 at time of this posting)
  4. Download and install the Apache Felix Http Jetty bundle:
    /opt/felix$java -jar bin/felix.jar 
    ____________________________
    Welcome to Apache Felix Gogo
    
    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (4.2.1)
        1|Active     |    1|Apache Felix Bundle Repository (1.6.6)
        2|Active     |    1|Apache Felix Gogo Command (0.12.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.10.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.10.0)
    g! install file:/opt/felix/examples/setup/org.apache.felix.http.jetty-2.2.0.jar
    Bundle ID: 6
    g! start 6
    g! [INFO] Started jetty 6.1.x at port(s) HTTP:8080

OSGi Example Bundles:

You will find the code for these 3 different bundles in the osgi-evaluation/examples/wiring packages.

  1. Date Service API – a simple API that provides a formatted date string given a Date
    package org.osgiexample.service.date;
    
    import java.util.Date;
    
    public interface DateService {
        public String getFormattedDate(Date date);
    }
  2. Date Service Impl – implementation of the Date Service API
    package org.osgiexample.service.date;
    
    import java.text.DateFormat;
    import java.util.Date;
    
    public class DateServiceImpl implements DateService {
        public String getFormattedDate(Date date) {
            return DateFormat.getDateInstance(DateFormat.LONG).format(date);
        }
    }
  3. HelloWorld Filter – extends Java ServletFilter.  Registers a simple servlet and itself.  When an HTTP request is filtered, adds “Hello World” to the response with a formatted date string obtained by the DateService
    package org.osgiexample.filters.helloworld;
    
    import org.apache.felix.http.api.ExtHttpService;
    import org.osgiexample.service.date.DateService;
    
    import javax.servlet.*;
    import java.io.IOException;
    import java.util.Date;
    
    public class HelloWorldFilter implements javax.servlet.Filter {
    
        DateService dateService;
        ExtHttpService httpService;
    
        public HelloWorldFilter(DateService dateService, ExtHttpService httpService) {
            this.dateService = dateService;
            this.httpService = httpService;
    
            httpService.registerServlet("/", new SimpleServlet(), null, null);
            httpService.registerFilter(this, ".*", null, 0, null);
        }
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            Date now = new Date();
            chain.doFilter(request, response);
            response.getWriter().write("Hello World\n" + dateService.getFormattedDate(now));
        }
    
        public void destroy() {
        }
    
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    }

Next Posts:

IntelliJ IDEA – enable Java 1.4 assertions for Junit Run/Debug configurations

I recently ran into a test discrepancy where my test was failing when running it via the maven surefire plugin, yet it passed when I ran it through IntelliJ’s JUnit runner.

After spending a ridiculous amount of time on this issue, I was finally able to pinpoint the discrepancy to the Java 1.4 introduced “assert” statement and the differences in the default behavior of the maven surefire plugin and the IntelliJ JUnit runner.  The maven surefire plugin (v 2.7.2) enables JVM assertions by default.  IntelliJ’s JUnit runner does not (v 9.0.4).  My test in question happened to be failing due to a failing assert in an included xml parsing library.

To change the default behavior of the JUnit runner, edit the Run/Debug configurations, select Edit Defaults, select JUnit, and add “-ea” or “-enableassertions” to the VM parameters.