Search code examples
javaspringspring-mvcosgiosgi-bundle

Spring MVC with OSGi - how to register new controllers - second part?


I have maven web application, what used Spring Web MVC and I use in main app @RequestMapping annotation and

<context:component-scan
       base-package="net.arturik.testosgispring.controllers" />
<mvc:annotation-driven />

in mvc-dispatcher-servlet.xml . All works OK, controllers correctly maps with @RequestMapping. It's OK.

But hell is starts when I trying to map new controller from OSGi bundle.

My bundle code is:

package net.arturik.testosgibundle;

import net.arturik.testosgispringlib.Vars;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

import org.osgi.util.tracker.ServiceTracker;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

//@Configuration //Specifies the class as configuration  
//@ComponentScan("net.arturik.testosgibundle.controllers") //Specifies which package to scan  
//@EnableWebMvc //Enables to use Spring's annotations in the code  
public class Activator implements BundleActivator {

    private static BundleContext context;
    private ServiceTracker httpServiceTracker;

    static BundleContext getContext() {
        return context;
    }

    public void start(BundleContext context) throws Exception {

        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("k:\\myhostingpanel\\myhostingpanel\\Tests\\TestOSGIBundle\\src\\main\\resources\\dispatcher-context.xml");

        System.out.println("STARTING MODULE!!! 2");
        Vars.qqq = "!!!!";
    }

Code of the controller, what I want map to the URL:

package net.arturik.testosgispring.controllers.q;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class C1 {

    @RequestMapping(value = "/77777", method = RequestMethod.GET)
    public ModelAndView getdata() {

        ModelAndView model = new ModelAndView("index");

        return model;

    }

}

Content of the dispatcher-context.xml file is

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/security 
        http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <context:annotation-config />
    <context:component-scan
        base-package="net.arturik.testosgispring.controllers.q" annotation-config="true" />

    <bean name="/helloWorld.htm"
          class="net.arturik.testosgispring.controllers.q.C1" />


    <mvc:annotation-driven />


</beans>

On activating of the bundle I got error:

18-Nov-2014 18:37:53.370 INFO [Thread-6] org.springframework.context.support.FileSystemXmlApplicationContext.prepareRefresh Refreshing org.springframework.context.support.FileSystemXmlApplicationContext@25796c7e: startup date [Tue Nov 18 18:37:53 MSK 2014]; root of context hierarchy
18-Nov-2014 18:37:53.378 INFO [Thread-6] org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions Loading XML bean definitions from file [k:\myhostingpanel\myhostingpanel\Tests\TestOSGIBundle\src\main\resources\dispatcher-context.xml]
18-Nov-2014 18:37:53.452 WARNING [Thread-6] org.springframework.context.support.FileSystemXmlApplicationContext.refresh Exception encountered during context initialization - cancelling refresh attempt
 org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [net.arturik.testosgispring.controllers.q.C1] for bean with name '/helloWorld.htm' defined in file [k:\myhostingpanel\myhostingpanel\Tests\TestOSGIBundle\src\main\resources\dispatcher-context.xml]; nested exception is java.lang.ClassNotFoundException: net.arturik.testosgispring.controllers.q.C1
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1325)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:623)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:592)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1394)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:957)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:705)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:140)
    at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:84)
    at net.arturik.testosgibundle.Activator.start(Activator.java:25)
    at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:645)
    at org.apache.felix.framework.Felix.activateBundle(Felix.java:2154)
    at org.apache.felix.framework.Felix.startBundle(Felix.java:2072)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:976)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:963)
    at khartn.khartnosgiwrapper.OSGiLoader.installAndStartBundles(OSGiLoader.java:175)
    at khartn.khartnosgiwrapper.OSGiLoader.start(OSGiLoader.java:90)
    at net.arturik.testosgispring.OSGIThread.run(OSGIThread.java:34)
Caused by: java.lang.ClassNotFoundException: net.arturik.testosgispring.controllers.q.C1
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1324)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1177)
    at org.springframework.util.ClassUtils.forName(ClassUtils.java:246)
    at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:395)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1346)
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1317)
    ... 18 more

Could not create framework: org.osgi.framework.BundleException: Activator start error in bundle net.arturik.TestOSGIBundle [1].
org.osgi.framework.BundleException: Activator start error in bundle net.arturik.TestOSGIBundle [1].
    at org.apache.felix.framework.Felix.activateBundle(Felix.java:2204)
    at org.apache.felix.framework.Felix.startBundle(Felix.java:2072)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:976)
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:963)
    at khartn.khartnosgiwrapper.OSGiLoader.installAndStartBundles(OSGiLoader.java:175)
    at khartn.khartnosgiwrapper.OSGiLoader.start(OSGiLoader.java:90)
    at net.arturik.testosgispring.OSGIThread.run(OSGIThread.java:34)
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [net.arturik.testosgispring.controllers.q.C1] for bean with name '/helloWorld.htm' defined in file [k:\myhostingpanel\myhostingpanel\Tests\TestOSGIBundle\src\main\resources\dispatcher-context.xml]; nested exception is java.lang.ClassNotFoundException: net.arturik.testosgispring.controllers.q.C1
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1325)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:623)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:592)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1394)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:957)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:705)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:140)
    at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:84)
    at net.arturik.testosgibundle.Activator.start(Activator.java:25)
    at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:645)
    at org.apache.felix.framework.Felix.activateBundle(Felix.java:2154)
    ... 6 more
Caused by: java.lang.ClassNotFoundException: net.arturik.testosgispring.controllers.q.C1
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1324)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1177)
    at org.springframework.util.ClassUtils.forName(ClassUtils.java:246)
    at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:395)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1346)
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1317)

Why Spring can't find class net.arturik.testosgispring.controllers.q.C1 from OSGI bundle package? Package also in in the Exports in Manifest:

Export-Package: net.arturik.testosgibundle;uses:="org.osgi.framework,org
 .springframework.context.support,net.arturik.testosgispringlib,org.osgi
 .util.tracker";version="1.0.0.SNAPSHOT",net.arturik.testosgibundle.cont
 rollers;uses:="org.springframework.web.servlet,org.springframework.ster
 eotype,org.springframework.web.bind.annotation";version="1.0.0.SNAPSHOT
 ",net.arturik.testosgispring.controllers.q;uses:="org.springframework.w
 eb.servlet,org.springframework.stereotype,org.springframework.web.bind.
 annotation";version="1.0.0.SNAPSHOT"
Import-Package: net.arturik.testosgispringlib,org.osgi.framework;version
 ="[1.7,2)",org.osgi.util.tracker;version="[1.5,2)",org.springframework.
 context.support,org.springframework.stereotype,org.springframework.web.
 bind.annotation,org.springframework.web.servlet

Solution

  • It appears that you created a separate bundle with the Spring stuff or got it from somewhere. As a result the classpath of the bundle containing the FileSystemXmlApplicationContext class cannot see your local classes. Hence the ClasssNotFoundException.

    You can of course tweak with classloaders, for example by setting the bundle class loader to the thread before creating the Context, but I would strongly recommend to move away from the Spring/OSGi combination.

    Spring (more specifically: the later versions with all the hidden magic) and OSGi do not really work together. This is commonly known and that's the reason why you don't get much response to your questions. Believe me, you are on a path that will cause a lot of difficulties and is likely to have a dead end.

    If you must use the combination, you are probably best off using an additional container like Apache Karaf. I don't use it, but I know others had some success with it.