Spring Integration: Inject request scoped twitter-template bean into inbound-channel-adapter - spring-integration

I have an annotation configured request-scoped TwitterTemplate bean and I want to inject that bean into an xml configured inbound-channel-adapter.
What is the best way to do that and are there any implications that need to be considered in case of multiple sessions accessing the same inbound-channel-adapter?
Have you got any examples of twitter inbound-channel-adapter configured through java?

Inject an ApplicationContext object into your xml configured bean, as a property.
Your xml configured bean can implement InitializingBean and override the afterPropertiesSet method, where you get an instance of your twitterBean as shown in the code below.
You context gets merged irrespective of the configuration mechanism you use.
YourXmlBean implements InitializingBean {
ApplicationContext ctx;
TwitterTemplate twitBean;
...
#Override
public void afterPropertiesSet(){
twitBean = (TwitterTemplate) ctx.getBean("twitterTemplate");
}

Related

Bean scope hierarchy and dependence? [duplicate]

I need to modify a user session object (SessionScoped bean - CDI) in a Servlet, so I have to obtain that bean somehow. I used injection in the following way:
#Inject
private UserSession user;
where UserSession is the SessionScoped CDI bean. user methods are called from either doPost or doGet servlet methods.
This works perfectly; every time the #Inject annotation injects the appropriate UserSession bean, but I don't understand how this behavior is achieved.
I assumed that the beans, annotated with #Inject, are injected only once (when the object - Servlet instance in this case - is created), but it is obviously a wrong presumption.
So, when are these beans injected into the servlet? Per request? And how does this approach avoids conflicts (one servlet instance - multiple threads to deal with it) when there are multiple UserSession objects?
The CDI uses the proxy pattern. The injected instance is actually not the real instance, but a proxy which locates the real instance depending on the current context and delegates all methods to it (like as how EJBs work). The autogenerated class of your UserSession bean looks roughly like this:
public UserSessionCDIProxy extends UserSession implements Serializable {
public String getSomeProperty() {
UserSession instance = CDI.resolveItSomehow();
return instance.getSomeProperty();
}
public void setSomeProperty(String someProperty) {
UserSession instance = CDI.resolveItSomehow();
instance.setSomeProperty(someProperty);
}
}
This mechanism allows you to inject instances of a narrower scope in instances of a broader scope and allows you to still get the expected instance in the current context. The standard JSF #ManagedProperty annotation doesn't support it, simply because it does not use a proxy, but injects the desired instance directly. That's why it's not possible to inject something of a narrower scope by #ManagedProperty.
See also:
Backing beans (#ManagedBean) or CDI Beans (#Named)?
Get JSF managed bean by name in any Servlet related class
When using #EJB, does each managed bean get its own #EJB instance?
How to choose the right bean scope?
Your answer lies in the C of CDI, which stands for Contexts.
What happens is that not the actual bean is injected, but a proxy. This proxy is contextual and resolves to the actual session scoped bean depending on the context of the caller on who's behalf the proxy is executed.

Inject an application scoped managed bean in a websocket

I'm developing a real time application. I have websockets and application scoped managed bean. I'm trying to access the application scoped managed bean from a websocket but I can't. Is this possible?
This is my websocket and managed bean (application scoped):
#ServerEndpoint("/mediador")
#ManagedBean(eager = true)
#ApplicationScoped
public class Mediador implements Serializable {
#ManagedProperty(value = "#{aplicacion}")
private Aplicacion aplicacion;
...
And my "Aplicacion" managed bean:
#ManagedBean(eager = true)
#ApplicationScoped
public class Aplicacion implements Serializable {
...
If I try to access in Mediador class to de managed property "aplicacion" it's null so I get a NullPointerException.
Thanks
This is really not right.
#ServerEndpoint("/mediador")
#ManagedBean(eager = true)
#ApplicationScoped
public class Mediador implements Serializable {
WS (JSR-356 WebSocket) API and JSF API are completely independent from each other. They know nothing from each other and won't take mixed annotations from each other into account.
Effectively, you end up with two instances of the class. One as a WS managed server endpoint as available by ws://.../mediador, and one as a JSF managed bean as available by #{mediador}. The #ManagedProperty is only recognized by JSF managed bean facility and it'll work in the JSF managed bean instance only.
Use CDI instead. It works across the entire Java EE web application. Not only in WebSocket endpoints, but also in JSF managed beans, WebServlets, WebFilters, WebListeners, JAX-RS resources, JAX-WS resources, etcetera. Eventually, JSF managed bean facility will be deprecated in favor of CDI. This will happen in Java EE 9 or perhaps already 8.
#ServerEndpoint("/mediador")
public class Mediador { // Shouldn't be serializable!
#Inject
private Aplicacion aplicacion;
// ... (no getter+setter needed!)
}
#Named
#ApplicationScoped // javax.enterprise.context
public class Aplicacion { // Shouldn't be serializable!
// ...
}
Unrelated to the concrete problem: implementing websockets in JSF rightly is not exactly trivial, certainly not if you'd like to take into account JSF session and view scopes, and would like to be able to target a specific user during push. You'd better look at an existing push component. See also How can server push asynchronous changes to a HTML page created by JSF?

Update faces-config.xml in memory at runtime

When a JSF/XPages application starts it reads the faces-config.xml for managed beans, validators etc. Can I manipulate the loaded configuration at runtime? e.g. dynamically add a validator to ensure my custom code will run.
I'm not trying to change the xml file at runtime, but the memory representation after it gets loaded.
XPages uses a JSF 1.x runtime,so JSF 2.0 constructs might not work
Yes, you can add a lot of JSF artifacts which are normally configured in faces-config.xml by among others the Application class as well.
Application application = FacesContext.getCurrentInstance().getApplication();
application.addValidator("fooValidator", "com.example.FooValidator");
// ...
You could do the job in an eagerly initialized application scoped managed bean.
#ManagedBean(eager=true)
#ApplicationScoped
public class Config {
#PostConstruct
public void init() {
// ...
}
}

How do I force an application-scoped bean to instantiate at application startup?

I can't seem to find a way to force an application-scoped managed bean to be instantiated/initialized when the web app is started. It seems that application-scoped beans get lazy-instantiated the first time the bean is accessed, not when the web app is started up. For my web app this happens when the first user opens a page in the web app for the first time.
The reason I want to avoid this is because a number of time-consuming database operations happen during the initialization of my application-scoped bean. It has to retrieve a bunch of data from persistent storage and then cache some of it that will be frequently displayed to the user in the form of ListItem elements, etc. I don't want all that to happen when the first user connects and thus cause a long delay.
My first thought was to use an old style ServletContextListener contextInitialized() method and from there use an ELResolver to manually request the instance of my managed bean (thus forcing the initialization to happen). Unfortunately, I can't use an ELResolver to trigger the initialization at this stage because the ELResolver needs a FacesContext and the FacesContext only exists during the lifespan of a request.
Does anyone know of an alternate way to accomplish this?
I am using MyFaces 1.2 as the JSF implementation and cannot upgrade to 2.x at this time.
My first thought was to use an old style ServletContextListener contextInitialized() method and from there use an ELResolver to manually request the instance of my managed bean (thus forcing the initialization to happen). Unfortunately, I can't use an ELResolver to trigger the initialization at this stage because the ELResolver needs a FacesContext and the FacesContext only exists during the lifespan of a request.
It doesn't need to be that complicated. Just instantiate the bean and put it in the application scope with the same managed bean name as key. JSF will just reuse the bean when already present in the scope. With JSF on top of Servlet API, the ServletContext represents the application scope (as HttpSession represents the session scope and HttpServletRequest represents the request scope, each with setAttribute() and getAttribute() methods).
This should do,
public void contextInitialized(ServletContextEvent event) {
event.getServletContext().setAttribute("bean", new Bean());
}
where "bean" should be the same as the <managed-bean-name> of the application scoped bean in faces-config.xml.
Just for the record, on JSF 2.x all you need to do is to add eager=true to #ManagedBean on an #ApplicationScoped bean.
#ManagedBean(eager=true)
#ApplicationScoped
public class Bean {
// ...
}
It will then be auto-instantiated at application startup.
Or, when you're managing backing beans by CDI #Named, then grab OmniFaces #Eager:
#Named
#Eager
#ApplicationScoped
public class Bean {
// ...
}
Romain Manni-Bucau posted a neat solution to this that uses CDI 1.1 on his blog.
The trick is to let the bean observe the initialization of the built-in lifecycle scopes, i.e. ApplicationScoped in this case. This can also be used for shutdown cleanup. So an example looks like this:
#ApplicationScoped
public class ApplicationScopedStartupInitializedBean {
public void init( #Observes #Initialized( ApplicationScoped.class ) Object init ) {
// perform some initialization logic
}
public void destroy( #Observes #Destroyed( ApplicationScoped.class ) Object init ) {
// perform some shutdown logic
}
}
As far as I know, you can't force a managed bean to be instantiated at application startup.
Maybe you could use a ServletContextListener which, instead of instantiating your managed bean, will perform all the database operations itself?
Another solution might be to instantiate your bean manually at application startup, and then set the bean as an attribute of your ServletContext.
Here is a code sample:
public class MyServletListener extends ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
MyManagedBean myBean = new MyManagedBean();
ctx.setAttribute("myManagedBean", myManagedBean);
}
}
In my opinion, this is far from clean code, but it seems like it does the trick.
Additionally to BalusC's answer above you could use #Startup and #Singleton (CDI), e.g.
//#Named // javax.inject.Named: only needed for UI publishing
//#Eager // org.omnifaces.cdi.Eager: seems non-standard like taken #Startup below
#Startup // javax.ejb.Startup: like Eager, but more standard
#Singleton // javax.ejb.Singleton: maybe not needed if Startup is there
//#Singleton( name = "myBean" ) // useful for providing it with a defined name
#ApplicationScoped
public class Bean {
// ...
}
which is nicely explained here.
Works in JPA 2.1 at least.

Jsf custom managed bean instantination handler

Which JSF 1.2 component is responsible for instantiating managed bean specified in faces-config.xml?
I'd like to replace this component with my custom-made version which will perform some additional tasks after bean instance is successfully created.
No one component is responsible for that. It is just EL which is responsible for that. If the expression #{beanname} returns null, it will create one which is associated with the managed bean name.
In your specific case, the normal way to solve this problem is just making use of the constructor of the bean or a public method of the bean annotated with #PostConstruct.
public class Bean {
public Bean() {
// Put code here which is to be executed during construction, but before
// setting of the managed properties (<managed-property> declarations).
}
#PostConstruct
public void init() {
// Put code here which is to be executed AFTER construction
// and the setting of managed properties.
}
}
If you really want to take the EL resolving in your own hands, then best what you can do is to implement a custom ELResolver. You can find here an article about that.
Here is the JSP resolver structure detailed in the JSF 1.2 spec:
Faces ELResolver for JSP
|_ faces.ImplicitObjectELResolverForJSP
|_ faces.ManagedBeanELResolver
|_ faces.ResourceBundleELResolver
|_ ELResolvers in application configuration resources
|_ faces.VariableResolverChainWrapper (wraps deprecated API)
|_ faces.PropertyResolverChainWrapper (wraps deprecated API)
|_ ELResolvers from Application.addELResolver()
Managed beans will be instantiated by the faces.ManagedBeanELResolver (which is just a label developers can refer to it by, not the name of a public class).
The top-level ELResolver is provided via the Application (which you can provide via an ApplicationFactory). But, although the JSF specification details behaviour, the API does not expose the means by which the managed beans will be instantiated. It would be difficult to decorate the implementation to disambiguate between a newly instantiated bean and a bean that was returned from the request/session/application scope.
BalusC's post gives a couple of good strategies for approaching this problem.
Although JSF 2.0 brings changes to the managed bean facility, it does not, to the best of my knowledge, change this aspect of the API.
#PostConstruct is the way to go for JSF 1.2.
If you are using JavaEE 6 then you can also use #Produces annotation on a method to create custom factory method.
public class CustomBeanFactory {
#Produces
public Bean getBean() {
Bean bean = new Bean();
System.out.println("Created new bean.");
return bean;
}
}

Resources