unable to expose osgi service bean as class not interface - spring

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.

Related

Osgi Inject bean into Activator

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.

Spring - Create an instance of one class using the factory method of another class

I am using Apache Ignite in my Spring project. I want to create an instance of org.apache.ignite.Ignite within my application context using xml configuration. One of the way to create the Ignite object is by using org.apache.ignite.Ignition#start method. My question is, how can i use bean xml configuration to create an instance of Ignite from Ignition#start.
<!-- Implements Ignite interface -->
<bean class="org.apache.ignite.internal.IgniteKernal">
</bean>
<!-- Returns instance of Ignite as org.apache.ignite.internal.IgniteKernal -->
<bean id="ignitionIgniteKernal" class="org.apache.ignite.Ignition" factory-method="start">
<constructor-arg ref="refToConfig" />
</bean>
Try using the Spring cache Manager.
http://apacheignite.gridgain.org/docs/spring-caching
As per documentation
The embedded node can be started by SpringCacheManager itself. In this case you will need to provide a path to Ignite configuration XML file or IgniteConfiguration bean via configurationPath or configuration properties respectively (see examples below). Note that setting both is illegal and results in IllegalArgumentException.
So the application context brings up the cache and then spring cache manager manages the cache via annotation or explicit addition.
Hope this helps.
According to the spring documentation, the "ignitionIgniteKernal" bean definition above is exactly how you would create an instance of org.apache.ignite.internal.IgniteKernal. Ref:
If the "class" attribute is present, the factory method will be a
static method on the class specified by the "class" attribute on this
bean definition. Often this will be the same class as that of the
constructed object - for example, when the factory method is used as
an alternative to a constructor. However, it may be on a different
class. In that case, the created object will not be of the class
specified in the "class" attribute. This is analogous to FactoryBean
behavior.

Exporting Spring Bean Service in OSGI- New Instance per Injection Call

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>

Camel - Using beans available in jar

I am using Spring's Application context for bean registry. I will be dependent on external jars for some services, which will be a part of routes.
Is there any way to let camel auto-register the beans that are available in the jar?
No, but you can call any java class from Camel using its bean component. You can specify a class name, and a method to invoke.
You can use the beanType attribute
<bean beanType="com.foo.MyClass" method="someNameHere"/>
Or in an uri
<to uri="bean:com.foo.MyClass?method=someNameHere"/>

akka-camel 2.2.1 route definition using Spring XML

I am using akka-camel 2.2.1 and need to configure routes to and away from Consumer and Producer actors, respectively. I am currently defining routes and adding them to the internal Camel context within the CamelExtension programmatically like so:
camel.context.addRoutes(new RouteBuilder {
def configure() = {
from("file:/tmp?include=whatever.*.log&noop=true&sendEmptyMessageWhenIdle=true")
.split(body(classOf[String]).tokenize("\n"))
.streaming()
.to("seda:input-route")
from("seda:update-route")
.to("bean:db-update-bean?method=process")
}})
I have an Actor that extends Consumer which reads from "seda:input-route" via its endPointUri, and another Actor that extends Producer that writes to "seda:update-route". The "db-update-bean" in defined in a Spring applicationContext.xml like so:
<bean id="db-update-bean" class="nz.co.whatever.DBUpdate">
<constructor-arg ref="jdbcTemplate"/>
<constructor-arg value="some_other_constructor_arg"/>
</bean>
The Spring context is loaded and started in a supervisor Actor started by akka.Main. However (and understandably), Camel is unaware of this Spring context, and thus went to great lengths to inform me that it had no clue what the "db-update-bean" was:
2013-10-11 08:55:09,614 [SedaConsumer ] WARN Error processing exchange. Exchange[Message: 1378642997698,27684,true,57.000000,0.750000,97]. Caused by:
[org.apache.camel.NoSuchBeanException - No bean could be found in the registry for: db-update-bean]
Of course, I could programmatically add the components to the akka-provided CamelContext, or else do something like this:
from("seda:update-route")
.bean(new DBUpdate(jdbcTemplate, "gps_temp_status"), "process")
but I would rather use Spring to define beans. Clearly, the CamelExtension needs to use the Spring-defined CamelContext rather than creating one of its own.
Furthermore, and more importantly, I would like to externalize the definition of the Camel routes into the same applicationContext.xml within a <CamelContext/> tag. Accoring to articles such as https://weblogs.java.net/blog/manningpubs/archive/2013/02/13/akka-and-camel, it seems the way to do so is to instantiate a "camel-service" bean and inject the Spring-defined CamelContext as so:
<camel:camelContext id="camelContext">
</camel:camelContext>
<akka:camel-service id="camelService">
<akka:camel-context ref="camelContext" />
</akka:camel-service>
Here is where the wheels come off. According to Roland Kuhn's reply in Why spring integration doc for akka exists only for 1.3.1 but not for next versions, the akka-spring library is not included in Akka 2.2.1, and thus there is no Spring namespace handler for akka, and I'm unable to instantiate this camel-service bean. Though not for lack of trying. Or cursing.
And so (finally), the question: How does one define Camel routes in Spring XML whose endpoints can be used by Consumer or Producer Actors using akka-camel 2.2.1 without akka-spring? Does one instantiate a Factory bean that produces a CamelService with a CamelContext injected or some other such witchcraft? Secondarily (but related) how can I use Spring to instantiate beans to be referenced in camel routes if I am forced to define them via a RouteBuilder?
Thanks in advance.

Resources