I am trying to export a spring bean as service using Spring's application context, I need to have them exported as "prototype" scope, but this is not possible due to OSGi Service registry caching the service as singleton.
Doing some research I came upon a post suggesting to use "session" scope to get around this issue. I am following this tutorial to get this working, but I am stuck with an issue that has to do with class loader not finding an interface.
Here's how I am declaring the bean
<osgi:service id="SimulationExporter" ref="simulationService" interface="org.geppetto.core.simulation.ISimulation"/>
<bean id="simulationService" scope="session" class="org.geppetto.simulation.SimulationService">
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
When exporting the bean to another bundle, I get the following error
Caused by: java.lang.IllegalArgumentException: interface org.springframework.aop.scope.ScopedObject is not visible from class loader
at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:484)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:713)
at org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:117)
The bundle importing the service bean has the dependency org.springframework.aop-3.0.0.RELEASE , and this has also being copied to the virgo repository. Any ideas why would the class loader not find that interface that it needs for scope "session"?
Does your MANIFEST.MF include import packages for aop.scope?
If you are using Apache Felix to generate it try adding something like this:
<Import-Package>org.aopalliance.aop,org.springframework.aop,org.springframework.aop.scope,org.springframework.aop.framework,*</Import-Package>
Related
I have an older Web-Application using Eclipse RAP 3.0 with Equinox OSGI-Container and Gemini Blueprint 1.0.2.
I can define my JDNI Values in server.xml
link them in context.xml and use them in my web.xml.
In my launch.ini i use the parent classloader fwk so the JNDI configuration is passed to the OSGI-Container.
My Application-Bundles can read those values for example in Bundle-Activator:
String xxx= InitialContext.doLookup("java:comp/env/xxx"); or
String xxx= new InitialContext().lookup("java:comp/env/xxx");
Some Bundle-Configuration is done via Gemini Blueprint xml files and SpringConfiguration Java classes.
<jee:jndi-lookup id="xxx" jndi-name="java:comp/env/xxx" />
This part is not working and i get following error
Error creating bean with name 'xxx': Invocation of init method failed;
nested exception is javax.naming.NameNotFoundException:
Name [java:comp/env/xxx] is not bound in this Context. Unable to find [java:comp].
I get the same Error when i use Spring-Java-Configuration which is invoked from gemini blueprint xml. Then statements like new InitialContext().lookup("java:comp/env/xxx") don't work and i get the same exception.
I think it has to to with the classloaders that are different for Bundle-Activator-Code and Gemini BlueprintExtender Thread but in can't figure it out how to solve this.
I found a Solution that i can use.
If i Move my JNDI-Lookups from xml into my Spring-Configuration-class then i can change the clasloader in init like this:
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
After that i my Lookups work fine.
i found that solution here
Can Spring Boot be used with OSGi? If not, any plans to have an OSGi Spring Boot?.
I would like to export spring bean from one bundle context to another. Problems begin when this bean doesn't have an interface such as MongoClient. First bundle context register Mongoclient, but when I want to expose it to another one I get: "no bean could be found in the registry for mongo of type: com.mongodb.Mongo" from reference bundle. Is there any way to define a bean in OSGi registry by class, not interface?
Exception comes from reference bundle:
Exception in thread "SpringOsgiExtenderThread-86"
org.apache.camel.RuntimeCamelException:
org.apache.camel.FailedToCreateRouteException: Failed to create route
article-author-getAll at: >>> Filter[{in ([header{operationName} ==
getAllAuthors])} -> [SetHeader[CamelMongoDbLimit, {2}],
To[mongodb:mongo?database=xxxx&collection=xxxx&operation=findAll],
Log[after db select getAllAuthors ${body}]]] <<< in route:
Route(article-author-getAll)[[From[activemq:queue:backend.au...
because of Failed to resolve endpoint:
mongodb://mongo?collection=xxx&database=xxxx&operation=findAll
due to: No bean could be found in the registry for: mongo of type:
com.mongodb.Mongo
In service bundle, everything looks good!
code looks like this in service bundle:
<bean id="mongoDatasource" class="com.mongodb.MongoClient">
<constructor-arg name="uri" ref="mongoClientUri" />
</bean>
<bean id="mongoClientUri" class="com.mongodb.MongoClientURI">
<constructor-arg name="uri" value="${mongo_host}" />
</bean>
Code from reference bundle context:
<reference id="mongoDataSourceReference" bean-name="mongoDatasource"
context-class-loader="service-provider"
interface="com.mongodb.MongoClient"/>
MongoClient doesn't have interface and osgi:reference must have defined interface property.
I've tried to extend MongoClient class and implements Interface and then expose it to osgi registry I received it properly in reference bundle but then I got exception from camelMongo where I must define only MongoClient class!
Camel Mongo route look like this:
from("direct:findAll")
.to("mongodb:MYMONGOCLIENTBEAN?database=flights&collection=tickets&operation=findAll")
Camel mongo route expect MongoClient bean in connection string.
So is there any way to define the bean in osgi registry by class, not interface?
or I should define MongoClient bean in the same bundle as camelMongo ?
Before getting a reference to existing OSGi service bean, you first need to export this bean as an OSGi service:
<osgi:service ref="beanToPublish" interface="com.xyz.MyService"/>
Although recommended, your service class does NOT need to implement an interface.
See the specs:
https://docs.spring.io/spring-osgi/docs/current/reference/html/service-registry.html#service-registry:export
The OSGi Service Platform Core Specification defines the term service
interface to represent the specification of a service's public
methods. Typically this will be a Java interface, but the
specification also supports registering service objects under a class
name, so the phrase service interface can be interpreted as referring
to either an interface or a class.
So in theory nothing should prevent you from getting a reference to your Mongo bean using the full classname.
I have 3 classes , one is Activator and two others, 'mysqlConfiguration' and 'BinaryLogListner' where 'mysqlConfiguration' is injected into 'BinaryLogListner' using blueprint.
This is my blueprint (the injection part):
<bean id="binaryLogListnerBean" class="cdc.mysql.BinaryLogListner">
<property name="mysqlConfiguration" ref="configManagementMysql"></property>
</bean>
I want to start the BinaryLogListner when the bundle starts , so I instanciated it from the Activator class with :
BinaryLogListner binaryLogListner = new BinaryLogListner();
When i try to use 'mysqlConfiguration' which is injected into 'BinaryLogListner' I will get a null pointer Exception.
I want to know how to inject a bean into an activator, is this possible ?
Any thougts how to start beans in these situations?
In the Activator you instantiate the class using new BinaryLogListner(). So you simply get the plain class without any blueprint injects. These injects only work when the bean instance is created by blueprint.
Instead of an Activator you should simply use an init-method on any blueprint bean to react on the (blueprint) activation of the bundle.
Generally whenever you use blueprint in a bundle you should not also use an Activator.
I want to make a call to a Spring bean (a #Component) from my message-driven bean (MDB) but have problems getting a reference to it. I've tried with a class implementing org.springframework.context.ApplicationContextAware which stores the Spring ApplicationContext in a static field in a class MyAppContext. The static field in MyAppContext is then accessed from the MDB. But MyAppContext is loaded from different classloaders. The Spring application context is correctly set in the web module classloader context, but in the MDB's classloader context, it's null.
Can I somehow instruct JBoss to use the same classloader for the web app and the MDB?
Or is there a better way than storing the Spring application context in a static field?
Thanks for any advice!
A static holder for the context is not really a good idea. To make your beans available to other applications in a Java EE environment, you should consider making use of JNDI.
Unfortunately, there is no plain JNDI exporter available out of the box, but it's fairly easy to write one yourself, as shown in this blog post: http://maestro-lab.blogspot.ro/2009/01/how-to-export-spring-managed-bean-to.html
There is however a JndiRmiServiceExporter that you may want to look at.
Once your beans are bound to names in JNDI, they can be referenced using standard CDI in your message bean without worrying about class loading issues.
Why not use "ClassPathXmlApplicationContext" to load and look up for the Spring bean you require in your MBean?
I have problems with loading files in SpringDM on Virgo. The reason is of course me, I am doing something wrong.
This is the situation:
bundleA contains a class to perform some generic initialization (fill tables with data from a generic configuration file).
bundleB contains, among others, a more specific version (extends) of the initialization class from bundleA (in spring file, I also specify that class from bundleA is parent of the more specialized class in bundleB)
bundleC is a web bundle, calls bundleB (which in turns first calls bundleA)
However, bundleB/bundleA does not seem to be able to find the configuration file. I get java.io.FileNotFound exception (file does not exist).
I defined the configuration file in bundleA as a classpath resource:
<bean id="myBeanId" class="org.springframework.core.io.ClassPathResource">
<constructor-arg>
<value>configfile.cfg</value>
</constructor-arg>
</bean>
The bean gets created and injected into the initialization class with Autowired annotation. However, as soon as I try to use the file, I get the exception.
Is there any "general" flaw in my approach? Should I be using other Resource loader? Any other suggestions?
If a part of the question is not clear, let me know, I will try to clarify...
Thanks!