Using OSGi service in the camel route - spring

I am reading the book 'Camel in Action' and I am unable to work out an example (Section 4.3.4 OsgiServiceRegistry) using OSGi service in the camel route. This is my bean (exposed as OSGi service
public class HelloBean {
public String hello(String name){
System.out.println(" Invoking Hello method ");
return "Hello " + name;
}
}
This is the spring XML file that exposes the above bean as service
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd">
<bean id="helloBean" class="camelinaction.testbeans.HelloBean" />
<osgi:service id="helloService" interface="camelinaction.testbeans.HelloBean" ref="helloBean" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start" />
<bean ref="helloService" method="hello" />
</route>
</camelContext>
</beans>
When I execute the maven goal 'camel:run', I get the following exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'helloService': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: required property 'bundleContext' has not been set
Please let me know how to set the bundleContext. I am using eclipse equinox as OSGi container.

camel:run just runs a thin non-OSGi runtime using the Spring Camel configs in your project. The message that you are getting is from SpringDM (the thing that instantiates the <osgi:service id="helloService"...>) not being able to locate an OSGi environment. To get this to work you need to install the code inside a supporting container - such as Karaf of Servicemix.
If you'd like to see OSGi working with Camel, check out the Servicemix Bootstraps project at https://github.com/FuseByExample/smx-bootstraps - full documentation is there around installing and tweaking the code. The bundles you'll be interested in there are smx-ponger and smx-ponger-service, which demonstrate the consumption and provision of OSGi services respectively.

I have run into situations like this in the past where I have OSGi dependent components in my camel route and I want to run/debug through an IDE like Eclipse.
If you are looking to debug while you develop, you can deploy to ServiceMix and remotely debug:
http://servicemix.apache.org/developers/remote-debugging-servicemix-in-eclipse.html
Camel 2.10 might support your scenario out of the box with OSGi blueprint:
http://camel.apache.org/camel-run-maven-goal.html

Spring OSGI extensions are fine, but as you can see it is a bit incestuous to test the service interface when you implement and declare the bean from the same spring context. You could of course have bean reference helloBean, but that defeats the purpose.
I am not sure of spring-osgi extension behavior, but at least with the very similar camel-blueprint with pojosr the same test can be with the modified helloService element.
<to uri="bean:camelinaction.testbeans.HelloBean" method="hello" />
Note the unusual fact that where bean id normally references a bean id you are now using the fully qualified interface.
Of course, this has some unfortunate limitations. It works fine if there is only one service instance implementing the desired interface, but there is no obvious way (to me) on how to apply a filter. One alternative in that case is to resort to actually using the bundleContext property of the CamelContext and using the programmatic API. But of course we would like to avoid that in favor of declarative approaches.

Related

How to create AOP interceptors for Mule classes?

This is what I've tried so far and my interceptor is not triggered (no "TATATA" in my logs) :
My interceptor AopLoggingInterceptor.java :
package fr.mycompany.bus.flow.reco.ani.custom.interceptor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class AopLoggingInterceptor {
#Around("execution(* org.mule.api.transport.MessageReceiver.routeMessage(org.mule.api.MuleMessage))")
public Object addMonitor(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("TATATA Before");
Object object = pjp.proceed();
System.out.println("TATATA After");
return object;
}
}
META-INF/aop.xml :
<aspectj>
<aspects>
<aspect name="fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor" />
</aspects>
<weaver options="-verbose">
<!-- Weave types that are within the org.mule.* packages. -->
<include within="org.mule.*" />
</weaver>
</aspectj>
My Mule/Spring config file :
<?xml version="1.0" encoding="UTF-8"?>
<mule >
<spring:beans>
<context:component-scan base-package="fr.mycompany.bus" />
<context:annotation-config />
<aop:aspectj-autoproxy />
<!-- Aspect -->
<spring:bean name="aopLoggingInterceptor" class="fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor" />
</spring:beans>
</mule>
My Mule file config consists of one flow with one inbound endpoint, 2 outbound endpoints, loggers and transformers (valid flow widely tested).
VM args :
-XX:PermSize=128M -XX:MaxPermSize=256M -javaagent:D:\path\to\mule\opt\aspectjweaver-1.6.11.jar
Extract from mule file starting in Eclipse which shows weaving is created :
[MuleApplicationClassLoader#2934847] info AspectJ Weaver Version 1.6.11 built on Tuesday Mar 15, 2011 at 15:31:04 GMT
[MuleApplicationClassLoader#2934847] info register classloader org.mule.module.launcher.MuleApplicationClassLoader#2934847
[MuleApplicationClassLoader#2934847] info using configuration /D:/BusToolBox/workspaces/dev/.mule/apps/bus-esb-mrc-reco-ani/classes/META-INF/aop.xml
[MuleApplicationClassLoader#2934847] info register aspect fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor
EDIT
It works nicely with a class included in my project, but not with mule classes :
[MuleApplicationClassLoader#6ad5934d] debug generating class 'fr.mycompany.bus.flow.reco.ani.custom.transformer.CustomerDetailToSiebelRecoAniOutputTransformer$AjcClosure1'
EDIT 2
Here is the best result I can get (by using <context:load-time-weaver />), the loading process tries to look for more classes loaded by difference classloaders is , but it results in :
ERROR 2014-08-08 16:00:46,802 [main] org.mule.module.launcher.application.DefaultMuleApplication: null
java.lang.IllegalStateException: ClassLoader [org.mule.module.launcher.MuleApplicationClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar
If I try to use spring-instrument-3.2.1.RELEASE.jar, I get same result as before (only main classloader is seen). Does it mean there is no hope with Mule ?
Have a look at this example for using Mule and Spring AOP. The example shows how to invoke Around advice for a component, but should be similar for the interceptor.
There is something very important when working with Spring AOP. In spring aop documentation is stated:
Use the simplest thing that can work. Spring AOP is simpler than using
full AspectJ as there is no requirement to introduce the AspectJ
compiler / weaver into your development and build processes. If you
only need to advise the execution of operations on Spring beans, then
Spring AOP is the right choice. If you need to advise objects not
managed by the Spring container (such as domain objects typically),
then you will need to use AspectJ. You will also need to use AspectJ
if you wish to advise join points other than simple method executions
(for example, field get or set join points, and so on).
So if you want that your AopLoggingInterceptor is invoked for MessageReceiver method calls, that is not going to work because the MessageReceiver object is not managed by the Spring container. The Spring container doesn't "see" this objects.
In other words Spring-AOP cannot add an aspect to anything that is not created by the Spring factory. I found that statement here.

Spring approach for changing configuration source by environment

I'm new to Spring and trying to figure out the best way to handle the following scenario:
We have an application where for local development and testing, all configuration values are pulled from a Properties file. When the app is deployed on to the App Server (Websphere in this case), instead of properties file we use JNDI resource properties.
Is there an accepted way of handling this in Spring? For a non-Spring application I probably would have done something like this using a good ol' factory pattern to decide the config source. For Spring, I've seen examples that use different context XML files per environment (sounds messy), or make use of Spring "Profiles".
Is there a generally accepted practice for this scenario?
Spring profiles are rather new and they were added precisely to address your problems. Moreover they should deprecate all other workarounds like different context XML files you mention.
For the sake of completeness here is an example:
<beans profile="test">
<context:property-placeholder location="/foo/bar/buzz.properties" />
</beans>
<beans profile="prd">
<jee:jndi-lookup id="properties" jndi-name="foo/bar/name"/>
</beans>
Depending on which profile you choose during deployment/startup, only one of the beans above will be instantiated.
Another approach I've never tried but seems to fit your case is default-value attribute in jee namespace:
<jee:jndi-lookup id="properties" jndi-name="foo/bar/name" resource-ref="true"
default-value="classpath:foo.properties"/>
Not sure if this will help you though.
Assuming Spring 3.1, try using profiles like Tomasz suggested, but instead of setting individual JNDI values for production, use
<beans profile="prd">
<context:property-placeholder/>
</beans>
In Spring 3.1, ContextLoaderListener apparently pulls in JNDI props as a PropertySource by default, so with property-placeholder, when you need to access a value you can just use ${some/jndi/name} in applicationContext.xml or a #Value annotation.
To make sure the webapp gets the values from JNDI, add
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>prd</param-value>
</context-param>
to web.xml.
In your tests, set the system property 'spring.profiles.active' to 'test', and you'll get the values from the props file.
one way to go is you use jndi also for local dev and testing. You could define the same jndi name. I don't know what's your testing server, in practice we use jetty, and maven-jetty plugin to test. It is lightweight and can run from your ide.
another way is like what you said in your question. Making use of Spring profile. Then you could declare different transactionManager beans with same id/name. of course they should be in different profiles. At runtime you could decide which profile should be activated, that is, which bean should be used.

Combine OSGi blueprint and spring configuration

Are there any good/best practices regarding the combination of Spring configuration and OSGi Blueprint (e.g. Gemini Blueprint)? Which XML files do you use? Where do you put them in your OSGi bundles (META-INF/spring, OSGi-INF)? Which of these practices will allow you to reuse your bundles in combination with a non-Gemini-implementation of Blueprint?
Background: We are in the process of switching from Spring/Spring DM to Spring/Blueprint. I am aware of Blueprint defining a <bean> element. However we occasionally face the situation that the limited bean definition capabilities of the Blueprint specification do not meet all our needs. So it seems to be a good choice to use Spring configuration within our bundles and Blueprint for wiring bundles via OSGi services.
Which XML files do you use? Where do you put them in your OSGi bundles
(META-INF/spring, OSGi-INF)? Which of these practices will allow you
to reuse your bundles in combination with a non-Gemini-implementation
of Blueprint?
Gemini Blueprint treats both of these directories equally, but OSGI-INF/blueprint/*.xml is the only one specified in the generic OSGi Blueprint specification.
A suggested practice from the Gemini Blueprint documentation is:
[...] A
suggested practice is to split the application context configuration
into at least two files, named by convention modulename-context.xml
and modulename-osgi-context.xml. The modulename-context.xml file
contains regular bean definitions independent of any knowledge of
OSGi. The modulename-osgi-context.xml file contains the bean
definitions for importing and exporting OSGi services. It may (but is
not required to) use the Gemini Blueprint OSGi schema as the top-level
namespace instead of the Spring 'beans' namespace.
I tried this, and it works great. I use Gemini Blueprint for one of my projects which has the files META-INF/spring/context.xml, which defines my beans and their relationships, and META-INF/spring/osgi-context.xml, which defines which beans to expose as/import from OSGi services and how. context.xml looks like
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="myOrdinarySpringBean" class="com.acme.impl.Foo"/>
</beans>
and is a regular ordinary Spring application context with no Blueprint/OSGi configuration at all. osgi-context.xml looks like
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<service id="myOsgiService" ref="myOrdinarySpringBean" interface="com.acme.Foo"/>
</blueprint>
You could, of course, use the <beans> namespace and root element here as well, but you'd have to define a xmlns:osgi and prefix the service like so: <osgi:service .../> for that to work. In my case I don't need the Gemini specific Blueprint stuff, so I'm happy with this generic Blueprint configuration. Likewise, I could use the <blueprint> namespace in context.xml as well, but this particular application is an old one being ported to OSGi, so I prefer to keep that configuration Spring specific for now.
Another application in turn has its own osgi-context.xml like
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<reference id="myOrdinarySpringBeanImportedFromOsgi" interface="com.acme.Foo" availability="mandatory"/>
</blueprint>
and at this time doesn't, but could, have its own context.xml like
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="myOrdinaryOtherSpringBean" class="com.acme.impl.Bar">
<property name="foo" ref="myOrdinarySpringBeanImportedFromOsgi"/>
</bean>
</beans>
and couldn't really care less whether myOrdinarySpringBeanImportedFromOsgi is imported from an OSGi service or defined as a regular ordinary Spring bean in the same application context.
These META-INF/osgi-context.xml configurations could trivially be moved to OSGI-INF/blueprint/ if I want to decouple yourself from the Gemini Blueprint implementation, but for the time being I prefer to keep the two halves in the same place to avoid making a mess of the directory structure.
Blueprint files should go under OSGI-INF/blueprint/ and are named *.xml (typically blueprint.xml). This location is per the OSGi 4.2 Blueprint spec and will work with Aries or Gemini.
Spring-DM files (as you probably know) go under META-INF/spring/ and are also named *.xml (typically beans.xml)
Both files should be able to peacefully co-exist. They'll only work, though, if you have support for each container installed.
Wiring should be done via the OSGi Service Registry.
As for migration, we have stayed on Spring-DM for capabilities that we couldn't do in Blueprint. Everything else has been migrated to Blueprint.

Spring component-scan in OSGi finds nothing

Using the Spring-Context MANIFEST definitions, I'm trying to do a component-scan to search packages for Spring annotated beans. My Spring XML configuration looks something like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<!-- Scans the classpath of this application for #Components to deploy as
beans -->
<context:component-scan
base-package="com.some.other.module.one,com.another.module.two" />
<context:annotation-config />
....
</beans>
In the MANIFEST, I import the packages containing the classes with Spring annotations. However, when I inspect the ApplicationContext, it doesn't have any of the annotated beans in it.
I believe this is happening because the classpaths we're scanning are in different bundles. Those bundles don't directly importing the packages with the classes that have Spring annotations in them. What's confusing is why Spring doesn't pick up the classpath of the main bundle that the component-scan is started from? It seems as if it is using the classpath of each bundle when it's doing a classpath scan. Is there a way to get the classpath scan to use the classpath of the bundle the scan starts in?
Edit
As Danail Nachev said below, when Spring does a classpath scan, it happens only within the module that the classpath is happening in. The work around is to use:
Put your configurations per module in a Spring 3 #Configuration bean.
Use an XML file in your top level bundle that initializes the #Configuration bean.
In the top level #Configuration bean use the #Import to import the other configuration files.
Make sure to Require-Bundle in your MANIFEST to ensure the configuration you're importing is available.
OSGi is all about being modular, so it makes great deal to have clear separation between the bundles. If Spring can go and unite them under single ApplicationContext, will not be different than usual Spring application, where everything is available in single classpath. Something like this.
What's happening is that each bundle receives its own ApplicationContext. These ApplicationContexts can exchange beans using OSGi Service Registry. You need to mark beans as exported and import them in others ApplicationContexts, otherwise they are not visible to one another.
This should explain why you cannot configure everything with single Spring context and expect that starting from one bundle it would go and find all beans. Spring context scans only single bundle and optionally can import/export beans as OSGi services.
Interpreted from here: Chapter 8. Packaging and Deploying Spring-based OSGi applications

Configuring a spring project

My question is : from basic which are the necessary jars that should required in Spring and how could we configure Spring project ?
Go to Spring home page and download Spring (Here, i am using 2.5.x version)
After installing, put the following jar in your classpath
<SPRING_HOME>/dist/spring.jar
Here goes a single bean
package br.com.introducing.Hello;
public class Hello {
private String message;
// getter's and setter's
}
...
Write a single xml to configure your beans as follows
// app.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="hello" class="br.com.introducing.Hello">
<property name="message" value="What do you want ?"/>
</bean>
</beans>
Put your app.xml in root classpath
And your psvm
public static void main(String [] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("app.xml");
Hello hello = (Hello) appContext.getBean("hello");
hello.getMessage(); // outputs What do you want ?
}
UPDATE
What is the role of the applicationContext.xml
When using getBean method, it behaves like a Factory pattern. Something like
public class ApplicationContext {
Map wiredBeans = new HashMap();
public static Object getBean(String beanName) {
return wiredBeans.get(beanName);
}
}
As said by Spring in Action book
It is a general-purpose factory, creating and dipensing many types of bean.
But, There is more
Allows you load files
You can publish events
It supports i18n (i18n stands for internationalization)
Suppose here goes messages.properties (root of the classpath)
// messages.properties
messsageCode=What do you want ?
To enable i18n, You must define a bean called messageSource to get advantage of our resource, as follows
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages"/>
</bean>
</beans>
Now, you can use it
appContext.getMessage("messsageCode", null, null); // outputs What do you want ?
Usually, we do not need to define all of our beans in xml file. You can use annotations (Additional settings needed to enable component scanning) instead of xml, Something like
package br.com.introducing.Hello;
#Component
public class Hello {
private String message;
// getter's and setter's
}
Component annotation says:
Spring, i am a general-purpose bean which can be retrieved through application context
A good resource about Spring is either Spring in Action book or Spring documentation
Advice: read carefully
You can have a look at the article on understanding the webapplicationcontexts and other xml config files in spring
Think this can help you in getting the configurations related to basic spring MVC with ease
You can also use Maven to create and manage projects. You can get an idea about Maven and how to start from here
A directory structure will be created by Maven and there will be a pom.xml inside your project directory. You can mention all dependencies in this file. Eg: for using spring, you can mention the dependency as follows,
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>2.5.3</version>
</dependency>
If you are using Eclipse as IDE, you need to execute the following command,
mvn eclipse:eclipse
This will create a .project file. You can now import the project into Eclipse IDE and start coding your application.
For beginners, Spring reference documentation and books like Spring in Action and Spring Recipes are very useful

Resources