Question

I'd like to use declarative service feature in my OSGI project for my servlets. In details: user is able to install module manually on the main application selecting some *.jar file, main application has embedded OSGI server and when the OSGI module is activated it should be registered for some requests For example in this way:

protected void startup() {
  MyServlet servlet = new MyServlet();
  if (httpService != null)  {
    httpService.registerServlet("/req", servlet, null, null); **//OK!**
  }
}

Unfortunately, I can't have httpService instance initialized and that's the problem. Here's the problem servlet module code listing:

@Component(name="app", immediate=true)
@Service(value=App.class)
public class App {                
        @Reference(name = "httpService", referenceInterface = HttpService.class, bind = "bindHttpService", unbind = "unbindHttpService")
        private HttpService httpService;

        @Activate
        protected void startup() {                    
            MyServlet servlet = new MyServlet();
            if (httpService != null)    {
                httpService.registerServlet("/req", servlet, null, null);
                //OK!
            } else {
                //Not OK! 
            }
        }

        protected void bindHttpService(HttpService httpService) {               
            this.httpService = httpService;
        }

        protected void unbindHttpService(HttpService httpService) {         
            this.httpService = null;
        }
        // some more code.........              
}

Maven bundle plugin settings pom.xml code

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
    <configuration>
        <instructions>
            <Bundle-SymbolicName>app</Bundle-SymbolicName>
            <Embed-Dependency>!org.osgi.core</Embed-Dependency>
            <Embed-Transitive>true</Embed-Transitive>                                               
            <Import-Package>                        
             <![CDATA[ 
               org.osgi*,
               com.mynamespace                        
            ]]>                     
            </Import-Package>                       
        </instructions>
    </configuration>
</plugin>

And here is simplified code for embedded OSGI server on main application:

public static void main(String[] args) 
{
    FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next();
    Map<String, String> config = new HashMap<String, String>();
    config.put(Constants.FRAMEWORK_STORAGE_CLEAN, "onFirstInit");
    config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "javax.microedition.io");
    Framework framework = frameworkFactory.newFramework(config);
    framework.start();
    BundleContext context = framework.getBundleContext();
    List<Bundle> installedBundles = new LinkedList<Bundle>();
    // install prerequisites
    installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.equinox.util_1.0.500.v20130404-1337.jar"));
    installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.osgi.services_3.4.0.v20131120-1328.jar"));
    installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.equinox.ds_1.4.200.v20131126-2331.jar"));
    //install servlet module
    installedBundles.add(context.installBundle("file:///MY_PATH\\app.jar"));
    for (Bundle bundle : installedBundles) {
        bundle.start();
    }
}

I was inspired by example from Peter Fries blog (http://www.peterfriese.de/osgi-servlets-flexibility-by-simplicity/), but I can't have httpService instance initialized. The App module even could be started only if @Reference annotation is removed or covered with comment, in other case module will not be activated.

I suspect that my embedded OSGI doesn't have some required module but can't get the details about it - log console doens't say anything.

UPDATE

Thanks for the hint Balasz!
There are my mistakes:
0. When <Embed-Dependency>!org.osgi.core</Embed-Dependency> is declared httpService can't be automatically binded through @Reference annotatoin, so bind = "bindHttpService", unbind = "unbindHttpService" is useless. I removed <Embed-Dependency> declaration and it helps to bind httpService like I want to have it (via bindHttpService).

  1. Before installing bundles on OSGI server jetty settings should be specified:

    System.setProperty("jetty.port","8080");
    System.setProperty("jetty.home.bundle", "org.eclipse.jetty.osgi.boot");

  2. There are too many jars must be installed on embedded OSGI server, in my case

    // Mandatory bundles installedBundles.add(context.installBundle("file:///MY_PATH\org.eclipse.equinox.util_1.0.500.v20130404-1337.jar")); installedBundles.add(context.installBundle("file:///MY_PATH\org.eclipse.equinox.ds_1.4.200.v20131126-2331.jar")); installedBundles.add(context.installBundle("file:///MY_PATH\org.eclipse.osgi.services_3.4.0.v20131120-1328.jar")); installedBundles.add(context.installBundle("file:///MY_PATH\javax.servlet-api-3.0.1.jar"));

            // Container bundles
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.jetty.security_8.1.12.v20130726.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.jetty.servlet_8.1.12.v20130726.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.jetty.continuation_8.1.12.v20130726.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.jetty.server_8.1.12.v20130726.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.jetty.util_8.1.12.v20130726.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.jetty.io_8.1.12.v20130726.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.jetty.http_8.1.12.v20130726.jar"));
    
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.equinox.http.servlet_1.1.400.v20130418-1354.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.equinox.http.jetty_3.0.200.v20131021-1843.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.equinox.http.servletbridge_1.0.300.v20130327-1442.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.equinox.servletbridge_1.3.0.v20130927-1541.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.equinox.common_3.6.200.v20130402-1505.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.equinox.registry_3.5.400.v20130717-1325.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.eclipse.equinox.http.registry_1.1.300.v20130402-1529.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\org.osgi.service.obr-1.0.2.jar"));
    
            // Service bundles
            installedBundles.add(context.installBundle("file:///MY_PATH\\jetty-httpservice-8.0.4.v20111024.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\ow2-httpservice-1.2-spec-1.0.0.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\jetty-osgi-boot-8.0.4.v20111024.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\jetty-deploy-8.0.4.v20111024.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\jetty-webapp-8.0.4.v20111024.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\jetty-security-8.0.4.v20111024.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\jetty-http-8.0.4.v20111024.jar"));
            installedBundles.add(context.installBundle("file:///MY_PATH\\jetty-xml-8.0.4.v20111024.jar"));
    
            // Finally, required OSGI bundle
            installedBundles.add(context.installBundle("file:///MY_PATH\\app.jar"));
    

So with these changes I have an initialized httpService object, and now I want to register my servlet instance

@Activate
protected void startup() {                    
   MyServlet servlet = new MyServlet();
   if (httpService != null) {
        System.out.println("Greetings! I just want to be sure that service isn't null!")
        //httpService.registerServlet("/req", servlet, null, null); // BAD PLACE
   } else {
        System.out.println("Something goes wrong")
   }
}

The code snippet above will show the 'Greetings' message but if I try to register servlet and uncomment 'BAD PLACE' the mesage won't be shown, nothing is happening. Exception is also couldn't be catched; looks like the 'startup' method is ignored. Any ideas what's wrong?

Was it helpful?

Solution

I do not see that you add any bundle that contains any servlet container (jetty or tomcat). I also do not see a bundle in your list that contains a HttpService implementation.

If you need a working example, see the dependencies here under the "Jetty with HTTP service" section. If you import those dependencies with their dependencies transitively, you will have a Jetty server with HttpService. In the example the dependencies are commented out as they are only used at development time. Please note that you must start the embedded servlet container in the way that the following system properties are defined:

jetty.port=8080
jetty.home.bundle=org.eclipse.jetty.osgi.boot

If you google, you can find other bundle sets for Tomcat or Jetty.

OTHER TIPS

So, the list of installed bundles is the following

// without these bundles http service won't be initialized
context.installBundle(libsDirectoryURL + "org.eclipse.equinox.util_1.0.500.v20130404-1337.jar");
context.installBundle(libsDirectoryURL + "org.eclipse.equinox.ds_1.4.200.v20131126-2331.jar");          
context.installBundle(libsDirectoryURL + "org.eclipse.osgi.services_3.4.0.v20131120-1328.jar");
context.installBundle(libsDirectoryURL + "org.eclipse.equinox.http.servlet_1.1.400.v20130418-1354.jar");

context.installBundle(libsDirectoryURL + "javax.servlet-api-3.0.1.jar");                                
context.installBundle(libsDirectoryURL + "jetty-httpservice-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-server-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-osgi-boot-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-deploy-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-continuation-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-servlet-8.0.4.v20111024.jar"));
context.installBundle(libsDirectoryURL + "jetty-webapp-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-server-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-security-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-http-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-io-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-util-8.0.4.v20111024.jar");
context.installBundle(libsDirectoryURL + "jetty-xml-8.0.4.v20111024.jar");

I'd like to use javax.servlet 3.1.0 with jetty 9.1.0 but couldn't solve the problem with jetty-httpservice which depends on org.eclipse.equinox.http.servlet (perhaps there is some version of this jar which works fine with javax.servlet 3.1.0 but I didn't find it)

I've posted a little code sample of the embedded OSGI server with HttpService on bitbucket, maybe someone find it usefull: https://bitbucket.org/vbashur/diff/src/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top