Arthur Khusntudinov Arthur Khusntudinov - 6 months ago 28
Java Question

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

Answer

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.