Wiring a prototype in blueprint - osgi

Like Spring, blueprint supports the prototype scope. But unlike Spring I can't see any documentation about how to use it.
In Spring you can ask the context to give you a new bean, what's the equivalent in the Blueprint world?

BlueprintContainer.getComponentInstance() does exactly what you are looking for.
osgi documentation:
A Blueprint Container represents the managed state of a Blueprint
bundle. A Blueprint Container provides access to all managed
components. These are the beans, services, and service references. A
Blueprint Container can be obtained by injecting the predefined
"blueprintContainer" component id.
Example
blueprint.xml:
<!-- blueprintContainer is predefined component here -->
<bean id="myService" class="myPackage.MyService">
<property name="container" ref="blueprintContainer"/>
</bean>
<!-- prototype which can be created from myService -->
<bean id="myPrototype" class="myPackage.MyPrototype" scope="prototype"/>
MyService.java:
// ...
// create new instance
MyPrototype myPrototype =
(MyPrototype) container.getComponentInstance("myPrototype");
pom.xml:
<!-- BlueprintContainer from Apache Aries-->
<dependency>
<groupId>org.apache.aries.blueprint</groupId>
<artifactId>org.apache.aries.blueprint.core</artifactId>
<version>1.3.0</version>
</dependency>

If a bean is of scope prototype then a new instance of the bean is created each time the bean is injected somewhere. Therefore each client that gets a bean of scope prototype injected gets a new instance of the bean.

Related

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.

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.

Why doesn't just autowiring a field in a GWT servlet in Spring work?

Simply marking a field as #Autowired in a GWT servlet does not work as intended. The code will compile and the web application will start up - which means Spring was successfully able to autowire the field, but when the servlet is actually hit by client-side code, it will yield a NullPointerException - like there's a different, uninitialized copy of the servlet being hit.
I've found several ways on the web to get this working, one is by using a base servlet class that does some Spring logic but doing this means every GWT servlet must extend this base class. The other way was by using AspectJ and the #Configurable Spring annotation. There was very little configuration involved here and it just magically worked.
My question is why doesn't just autowiring the field just work as intended? What is GWT doing that causes this to break.
The code will compile and the web application will start up - which
means Spring was successfully able to autowire the field
Not necessarily. The web container can instantiate a servlet without any help from Spring. Which you could be experiencing:
but when the servlet is actually hit by client-side code, it will
yield a NullPointerException - like there's a different, uninitialized
copy of the servlet being hit.
try overriding Servlet's init():
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
WebApplicationContextUtils.getWebApplicationContext(config.getServletContext())
.getAutowireCapableBeanFactory().autowireBean(this);
}
When the RPC service is called from the client, the "server-side" looking at the called URL and the servlets mapping will find the class, will make the instance and it will serve the request. Meaning if you have #Autowired annotation, or you already have an instance of the RPC class in the spring context, it does not matter. The new instance will be created and it won't "know" about Spring.
I resolve this by implementing a class which extends RemoteServiceServlet and implements Controller (from Spring MVC) and ServletContextAware.
This way you can map every RPC service by URL using the Spring MVC approach, for ex:
<bean id="publicUrlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/myFirstRpc">firstRpcServiceBeanRef</prop>
<prop key="/mySecondRpc">secondRpcServiceRef</prop>
</props>
</property>
</bean>
You also avoid the declarations for every single RPC servlet in web.xml, the mappings are clean and you have the Spring injection.
You declare only a single mapping in web.xml for org.springframework.web.servlet.DispatcherServlet which will serve all RPC calls.
There are couple of examples on the web with explanation about GWT RPC and Spring MVC controller integration.
Hope this will help.
It turns out that when using Spring at least, there's a MUCH simpler way to do this such that you can use #Autowired and it doesn't involve massive configuration or base classes. The caveat is that you must also use AspectJ. Here's what you need for your GWT servlet:
#Configurable
public class MyGwtServiceImpl extends RemoteServiceServlet implements MyGwtService
{
#Autowired
private MyService service;
// ...
}
And in your Spring config make sure you also have:
<!-- enable autowiring and configuration of non-spring managed classes, requires AspectJ -->
<context:spring-configured/>
One final note. If you are also using Spring security with your GWT application (and in your GWT servlets), you will need to make sure you define the correct mode to ensure the AspectJ weaving is done correctly (i.e., you get both #Secured annotation processing AND the #Autowired processing) you will need:
<!-- turn on spring security for method annotations with #Secured(...) -->
<!-- the aspectj mode is required because we autowire spring services into GWT servlets and this
is also done via aspectj. a server 500 error will occur if this is changed or removed. -->
<security:global-method-security secured-annotations="enabled" mode="aspectj"/>

Inject Spring beans into EJB3

I'm trying to inject Spring beans into an EJB using #Interceptors(SpringBeanAutowiringInterceptor.class) but I cannot get it working with the beanRefContext.xml examples I've seen.
Here's my EJB:
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class AlertNotificationMethodServiceImpl implements
AlertNotificationMethodService {
#Autowired
private SomeBean bean;
}
I've provided a beanRefContext.xml as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="...">
<!-- Have also tried with ClassPathXmlApplicationContext -->
<bean id="context"
class="org.springframework.web.context.support.XmlWebApplicationContext">
<property name="configLocations" value="/config/app-config.xml" />
</bean>
</beans>
But, it seems to be recreating the beans instead of obtaining the existing ApplicationContext. I end up with the following exception because one of my beans is ServletContextAware.
java.lang.IllegalArgumentException: Cannot resolve ServletContextResource
without ServletContext
When using the SpringBeanAutowiringInterceptor, shouldn't it obtain the ApplicationContext instead of create a new one?
I also tried changing my web.xml so the contextConfigLocation points to the beanRefContext.xml, hoping it'd load my Spring config but I end up with the same exception as above.
Does anyone know how to do this properly? The examples I've seen seem to use the same method I'm using which I assume means the beans are being recreated when the Interceptor is invoked (or is that how it's supposed to work and I've misunderstood).
When using the SpringBeanAutowiringInterceptor, shouldn't it obtain the ApplicationContext instead of create a new one?
Yes, and this is in fact what it does. It uses the ContextSingletonBeanFactoryLocator mechanism, which in turn manages a number of ApplicationContext instances as static singletons (yes, even Spring has to resort to static singletons sometimes). These contexts are defined in beanRefContext.xml.
Your confusion seems to stem from the expectation that these contexts have any relation to your webapp's ApplicationContext - they don't, they're entirely separate. So your webapp's ContextLoader is creating and managing a context based on the bean definitions in app-config.xml, and the ContextSingletonBeanFactoryLocator creates another one. They won't communicate unless you tell them to. The EJBs cannot get hold of the webapp's context, since EJBs sit outside of that scope.
What you need to do is to move the beans that need to be used by your EJBs out of app-config.xml and into another bean definition file. This extracted set of bean definitions will form the basis of a new ApplicationContext which will (a) be accessed by the EJBs, and (b) will act as the parent context of your webapp's context.
In order to activate the parent-child link between your webapp's context and the new context, you need to add an additional <context-param> to your web.xml called parentContextKey. The value of this parameter should be the name of the context defined in beanRefContext.xml (i.e. context, in your example).
The beans that stay behind in the webapp's context will be able to reference the beans in the parent context, as will the EJBs. However, the EJBs will not be able to reference anything in the webapp's context.
Also, you cannot use XmlWebApplicationContext in beanRefContext.xml, since that class requires awareness of the webapp, and ContextSingletonBeanFactoryLocator cannot supply that awareness. You should stick with ClassPathXmlApplicationContext there.

Resources