CDI newbie question. Simple test scenario: JSF + CDI SessionScoped beans.
I need an elegant way to instantiate a known set of session scoped CDI beans without mentioning them on a JSF page or calling their methods from other beans. As a test case - a simple logging bean, which simply logs start and end time of an http session.
Sure, I could create an empty JSF component, place it inside of a site-wide template and make it trigger dummy methods of the required session beans, but it's kinda ugly from my pov.
Another option I see, is to choose a single session bean (which gets initialized 100% either by EL in JSF or by references from other beans), and use its #PostConstruct method to trigger other session beans - the solution a little less uglier than the previous one.
Looks like I'm missing something here, I'd appreciate any other ideas.
While accepting the Karl's answer and being thankful to Luiggi for his hint, I also post my solution which is based on HttpSessionListener but does not require messing with BeanProvider or BeanManager whatsoever.
#WebListener
public class SessionListener implements HttpSessionListener {
#Inject
Event<SessionStartEvent> startEvent;
#Inject
Event<SessionEndEvent> endEvent;
#Override
public void sessionCreated(HttpSessionEvent se) {
SessionStartEvent e = new SessionStartEvent();
startEvent.fire(e);
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
SessionEndEvent e = new SessionEndEvent();
endEvent.fire(e);
}
}
To my surprise, the code above instantiates all the beans which methods are observing these events:
#Named
#SessionScoped
public class SessionLogger implements Serializable {
#PostConstruct
public void init() {
// is called first
}
public void start(#Observes SessionStartEvent event) {
// is called second
}
}
Yes, HttpSessionListener would do it. Simply inject the beans and invoke them.
If you container does not support injection in a HttpSessionListener you could have a look at deltaspike core and BeanProvider
http://deltaspike.apache.org/core.html
Related
This question already has answers here:
Get rid of org.jboss.weld.context.NonexistentConversationException, when a query-string parameter named cid is appended to the URL
(3 answers)
Closed 3 years ago.
I have a project with "Omnifaces 3.3" and "weld.servlet.shaded 3.0.5.Final".
I need to use a request parameter named "cid" in my application, but using it produces the next exception in Weld:
javax.servlet.ServletException: WELD-000321: No conversation found to restore for id 12312312
javax.faces.webapp.FacesServlet.service(FacesServlet.java:683)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
es.ine.sgtic.web.filter.SessionTimeoutFilter.doFilter(SessionTimeoutFilter.java:38)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:109)
I'm trying to rename the parameter that uses Weld internally using the next context-param, but it doesn't work, it keeps using "cid":
servletContext.setInitParameter("WELD_CONTEXT_ID_KEY", "weldCid")
I'm using JSF 2.3 with Spring, so my beans are managed by Spring with the annotation #Component. I've seen other solutions where they Inject #Inject private HttpConversationContext conversationContext; in an application bean, but it isn't available, and Spring doesn't find any implementation of that interface if I try to inject it in a bean.
How can I rename that parameter or get rid of it. I only use WELD in my project because Omnifaces requires it, but I don't really use anything from it.
Thanks.
After many tests, the only thing that worked was the next listener.
#WebListener
public class MyServletContextListener implements ServletContextListener {
#Inject
private HttpConversationContext conversationContext;
#Override
public void contextInitialized(ServletContextEvent sce) {
this.hideConversationScope();
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
// Not used
}
private void hideConversationScope() {
this.conversationContext.setParameterName(UUID.randomUUID().toString());
}
}
Here the object "conversationContext" was properly initialized and the renamed worked.
I would like to know if it's prohibited to use an EJB in an infinite thread(since it can't be given back to the container).
Something like this:
#ManagedBean(eager = true)
#ApplicationScoped
public class TestListenner {
private ResultThread result;
#PostConstruct
public void init() {
result = new ResultThread ();
Thread myThread = new Thread(result);
myThread.start();
}
public ResultThread getResult() {
return result;
}
}
And the thread:
public class ResultThread implements Runnable{
#EJB
private SomeService service;
private boolean continueWork = true;
public void run(){
while(continueWork){
service.doSomething();
//some proccessing
}
}
I'm working with EJB's since I started working with databases. I went over daofactories and the likes but I forgot about them(it was a year ago). I use them to do actions on my database when an user request a web page on my web app. But now I need to have a thread that calculate things in my database continuously to decrease the response time. If I cannot use EJB for the reason the container needs to have an handle on them, then what should I use ?
Hopefully I can use a class similar to what I'm used to use :
#Stateless
public class SomeServiceImpl implements SomeService {
#PersistenceContext(unitName = "my-pu")
private EntityManager em;
#Override
public void updateCategory(SomeClass theclass) {
em.merge(theclass);
}
}
Edit: The first answer by BalusC in this topic seems to imply that spawning threads in a ManagedBean wouldn't be dangerous in a case where no additional threads could be spawned. Since my bean is ApplicationScoped, which the web-app uses 1 and only 1 instance of it to do background work on the database (I've actually like a TOP 100 "posts" table that needs to be continually recalculated over time so I can query the table -with another bean- to have a fast answer).
What you have now won't work for at least one reason:
You can't inject resources into non-managed components. For the #EJB annotation to work, ResultThread ought to be a managed bean, and injected by the container. That means, that you must at least use CDI to inject it, rather than the new ResultThread you have now. What will work will look something like:
#Inject
private ResultThread result;
This way, the container gets in on the action.
The bottom line however, is that there are better ways of doing what you appear to be trying to do.
An EJB Timer
The new ManagedExecutor
Async EJBs
It may also interest you to know that EJBs are not allowed to spawn their own threads; in fact, it's frowned upon to do any handmade threading in the container. Why? The container is a managed environment - one where memory and concurrency have already been well thought out and designed. Your handspun thread breaks that model and any guarantees that the container may have been able to give you on your beans and other app components
Related:
Why is spawning threads in Java EE container discouraged?
You can't use your own Threads on Java EE container.
http://www.oracle.com/technetwork/java/restrictions-142267.html#threads
The Java EE spec provide TimerServices for this kind of work.
https://docs.oracle.com/javaee/6/tutorial/doc/bnboy.html
first of all, sorry for my bad english!
in the following managed Bean (ApplicationScoped), i access a ResourceBundle(.properties) as a #ManagedProperty. a ResourceBundle Object is not serializable, so i get in the Eclipse/Tomcat Console an Error saying that this object cannot be serialized/de-serialized.. etc.
Exception loading sessions from persistent storage
java.io.WriteAbortedException: writing aborted;
java.io.NotSerializableException: java.util.PropertyResourceBundle
i have 2 Questions to this issue:
i think, JSF handles pre-defined(in faces-config.xml) ResourceBundles as ApplicationScoped beans. this means(if i understanding this correctly), this Object/Bean (ResourceBundle) is been stored somewhere somehow in a file (persistent storage). Now and since ResourceBundle is not serializable, then in which format is it been stored? and how JSF serves such "Beans"? serialized Objects are stored in files as Bytes, so how not serializable Objects are stored?
in the following example, i would declare my #ManagedProperty ResourceBundle as transient (due to serialization problem), but transient objects won't be stored in persistent storage (stateless), does this mean that with every call of the method getConfigurationAttribute(where i use this resourceBundle) will recreate/reload the ManagedPropery ResourceBundle since it is marked as transient?
Your help is greatly appreciated.
#ManagedBean(name="facesResource",eager=true)
#ApplicationScoped
public class FacesResource implements Serializable{
private static final long serialVersionUID = 2454454363100273885L;
#ManagedProperty("#{FACES_CONFIG}")
private ResourceBundle facesConfig;
//private transient ResourceBundle facesConfig;
....
private Map<String,Language> languagesMap;
private Map<String,Theme> themesMap;
....
public FacesResource(){
}
#PostConstruct
public void init(){
System.out.println("*** FacesResource init ....");
try{
....
this.initLanguages();
this.initThemes();
....
}catch(Exception ex){
ex.printStackTrace();
}
}
public String getConfigurationAttribute(String attributeKey){
return this.facesConfig.getString(attributeKey);
}
// ... other methods & getter/setter ...etc
}
UPDATE:
the ResourceBundle in the FacesResource Bean is independent of the Request Locale, so its not a problem to load it in an ApplicationScoped Bean, BUT
since i access/inject(as #ManagedProperty) this ApplicationScoped Bean in other SessionScoped Beans, which should be serialized, which means, that all attributes (resourceBundle included) should be serialized too, and here i got the Problem with Serialization/Deserializazion
#BalusC: if i do like you suggest in your answer: ResourceBundle.getBundle("com.example.text"), i have to provide the baseName of the Bundle. BUT this is exactly what i want to avoid. i don't want to hardcode static Paths in java Source Codes), so that when the path changes(most unlikely, but for the Case), i don't like to change paths in Java Source Codes but only in faces-config.xml.
and i cannot use FacesContext.getCurrentInstance().getApplication().getResourceBundle(facesContext, "bundleVarName"); because my Bean is marked with eager=true, which means, the facesContext is NULL at this moment!
i think, JSF handles pre-defined(in faces-config.xml) ResourceBundles as ApplicationScoped beans.
Nope. They are managed by ResourceBundle API itself. JSF just resolves them on a per-request basis based on the requested locale (otherwise it would affect the language of any user visiting the web application!). So, they are essentially request scoped. But this all has further nothing to do with serialization. The ResourceBundle class is simply never intented to be serializable. It just lazily loads the bundles in Java's memory.
You'd best just do the same. Lazy loading it if it becomes null after deserialization. You only shouldn't evaluate #{FACES_CONFIG}, because it would be dependent on request locale. Provided that you can only use JSF <resource-bundle><var>, then you'd best load them via Application#getResourceBundle(). Provided a resource bundle var name of FACES_CONFIG, here's an example:
private transient ResourceBundle facesConfig;
public ResourceBundle getFacesConfig() {
if (facesConfig == null) {
FacesContext context = FacesContext.getCurrentInstance();
facesConfig = context.getApplication().getResourceBundle(context, "FACES_CONFIG");
}
return facesConfig;
}
By the way, the variable name facesConfig is very confusing. It namely suggests that it represents the contents of faces-config.xml.
See also:
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException
You can't use #ManagedProperty on a not Serializable Type.
Is it a resource bundle for localized Strings?
Read this: http://www.mkyong.com/jsf2/jsf-2-0-and-resource-bundles-example/
FacesContext facesContext = FacesContext.getCurrentInstance();
ResourceBundle resourceBundle = facesContext.getApplication()
.getResourceBundle(facesContext, "bundleName");
I've a Groovy project where I use RESTEasy with Weld and deploy to embedded Jetty. What I can't seem to get working is bean validation. RESTEasy documentation says that adding resteasy-validator-provider-11 along with hibernate validator dependencies (hibernate-validator, hibernate-validator-cdi, javax.el-api, javax.el) is enough. But the bean validation is simply ignored by RESTEasy. I curiously also get the following message in the logs:
plugins.validation.ValidatorContextResolver - Unable to find CDI supporting ValidatorFactory. Using default ValidatorFactory
Based on the suggestions on [this][1] post, I tried registering Hibernate InjectingConstraintValidatorFactory in META-INF/validation.xml but it depends on a BeanManager being injected and blows up at runtime.
The code can be found here https://github.com/abhijitsarkar/groovy/tree/master/movie-manager/movie-manager-web
A log gist is here: https://gist.github.com/anonymous/8947319
I've tried everything under the sun without any success. Pls help.
To do this without EE, I believe you'll need to fork the existing InjectingConstraintValidatorFactory but instead of using injection of the bean manager, use the CDI 1.1 class CDI to get a reference to the bean manager, e.g. CDI.current().getBeanManager(). http://docs.jboss.org/cdi/api/1.1/javax/enterprise/inject/spi/CDI.html
You do need to be on CDI 1.1 to do this (so Weld 2+, 2.1.1 is current I believe). Here's an example impl, based on: https://github.com/hibernate/hibernate-validator/blob/master/cdi/src/main/java/org/hibernate/validator/internal/cdi/InjectingConstraintValidatorFactory.java
public class InjectingConstraintValidatorFactory implements ConstraintValidatorFactory {
// TODO look for something with better performance (HF)
private final Map<Object, DestructibleBeanInstance<?>> constraintValidatorMap =
Collections.synchronizedMap( new IdentityHashMap<Object, DestructibleBeanInstance<?>>() );
private final BeanManager beanManager;
public InjectingConstraintValidatorFactory() {
this.beanManager = CDI.current().getBeanManager();
Contracts.assertNotNull( this.beanManager, "The BeanManager cannot be null" );
}
#Override
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
DestructibleBeanInstance<T> destructibleBeanInstance = new DestructibleBeanInstance<T>( beanManager, key );
constraintValidatorMap.put( destructibleBeanInstance.getInstance(), destructibleBeanInstance );
return destructibleBeanInstance.getInstance();
}
#Override
public void releaseInstance(ConstraintValidator<?, ?> instance) {
DestructibleBeanInstance<?> destructibleBeanInstance = constraintValidatorMap.remove( instance );
destructibleBeanInstance.destroy();
}
}
I finally fixed this. Turns out, a validation.xml is not really required, resteasy-cdi module does a fine job of registering the BeanManager. What I was missing and not clearly documented anywhere, is that if an annotation is placed on a method, the validation engine just "decides" what should be validated. I placed a #NotNull on a method and it was validating the return type, not the parameters. One can use validationAppliesTo element in some cases but #NotNull doesn't have it. When I moved it from the method to the parameter, it started working.
Now I ran across what I believe is a Weld bug but I'll post that question separately.
I have an object which I initialized manually (legacy code).
I'd like to put this object to the application context to make it available through CDI.
How do I do that without writing a CDI extension?
Using a producer. Make a bean that #Produces instances of your class.
Do you need something like that?
#ApplicationScoped
public class ApplicationScopedClass {
#Produces
public static ApplicationScopedClass makeAnInstance() {
return new ApplicationScopedClass();
}
}