Is it possible intercept a method from #ManagedBean? If not, there alternatives? - jsf

I'm new to JSF-2 and CDI (I'm from Spring world).
I want to intercept a method from #ManagedBean but my Interceptor class is never called. Is it possible to do?
LogInterceptor.java
#Interceptor
public class LogInterceptor {
#AroundInvoke
public Object log(InvocationContext ctx) throws Exception {
System.out.println("begin method interceptor");
Object methodReturn = ctx.proceed();
System.out.println("end method interceptor");
return methodReturn;
}
}
RoleMB
#ManagedBean
#ViewScoped
public class RoleMB extends BaseMB {
#Interceptors(LogInterceptor.class)
public void preEditRole(Role role) {
...
}
}
beans.xml
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>br.com.preventsenior.services.log.LogInterceptor</class>
</interceptors>
</beans>
The log(InvocationContext ctx) is never called.

Java EE interceptors work only on CDI managed beans and EJBs, not on JSF managed beans.
So, you've basically 2 options:
Change JSF bean management annotations by CDI bean management annotations (#Named et.al.)
Intercept on an EJB method instead which is in turn invoked by JSF managed bean. In a sane Java EE application, the real business logic belongs in EJBs anyway.

Related

JSF 2.3 CDI not working on tomcat

I am trying to set up jsf 2.3 on tomcat 8 whenever I used #inject I keep having an error with it I have googled and searched on stackoverflow.com yet I can't find a solution to it. I have already installed CDI (Weld) on it following #BalusC example from here How to install and use CDI on Tomcat? yet I keep having unsatisfied dependency: no bean matches the injection point. I can't figure it out is there anything i am missing?
ConfigurationBean.java
import static javax.faces.annotation.FacesConfig.Version.JSF_2_3;
import javax.faces.annotation.FacesConfig;
#FacesConfig(
// Activates CDI build-in beans
version = JSF_2_3
)
public class ConfigurationBean {
}
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>
faces-config.xml
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.3"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd">
</faces-config>
PushBean.java
#Named
#ViewScoped
public class PushBean implements Serializable {
#Inject #Push(channel="counter") //This is where i get the error message unsatisfied dependency: no bean matches the injection point
private PushContext push;
}
For me this code looks fine but am wondering if it is netbeans bug. I tried that without using spring just only tomcat with jsf i still get the same error message. I couldn't find any error message inside the stacktrace.
Spring is NOT a full blown CDI container and only 'knows' the #Named and #Inject annotations and consequently does not (most likely) recognize the #Push annotation as a qualifier and cannot find the bean and throws the error you get (posting an explicit error and stacktrace is btw something you should always do in a question!)
See also:
Inject Instance<Interface> : Spring and CDI compatibility
I'd suggest to check your scopes. The built - in CDI scopes are #ApplicationScoped, #SessionScoped, #ConversationScoped and #RequestScoped . There is no #ViewScoped annotation in CDI.
You can inject the same level or broader scope, but not one which is smaller (e.g you cannot inject #RequestScoped into #SessionScoped bean)

Why is a CDI Managed Bean in faces-config.xml not registered as an obersver?

I have implemented a CDI Bean which is observing events from another bean:
#SessionScoped
public class FixedItemController implements Serializable {
....
public void onWorkflowEvent(#Observes WorkflowEvent workflowEvent) throws AccessDeniedException {
logger.info("evaluate event...");
....
}
....
}
This works fine as long as I am using the bean in a JSF page with its default name 'fixedItemController'.
But if I declare another instance of that bean in the faces-config.xml like this:
<managed-bean>
<managed-bean-name>myOrderItemController</managed-bean-name>
<managed-bean-class>org.imixs.marty.workflow.FixedItemController</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>childItemProperty</property-name>
<property-class>java.lang.String</property-class>
<value>_orderItems</value>
</managed-property>
</managed-bean>
the second instance (myOrderItemController) is not registered automatically as an observer for my WorkflowEvent.
What can I do, to ensure that my second instance - declared by the faces-config.xml - will be immediately instantiated and registered as an observer to my workitemEvent?
faces-config.xml does not register CDI managed beans. It registers JSF managed beans. Effectively, your #{myOrderItemController} is a JSF managed bean. It's like as if you use #ManagedBean instead of #Named. The JSF bean management facility does not scan for CDI specific #Observes annotation.
Keep it a CDI managed bean. Whatever you tried to solve for which you thought that registering it in faces-config.xml would be the right solution has to be solved differently using the CDI API instead of the JSF API.

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?

Inject an EJB into a JSF managed bean

I have a war application with some JSF managed beans and EJB for some business logic. I'm using JSF 1.2, JBoss 5 and java 1.6
My managed bean:
#ManagedBean(name = "managedBean")
#SessionScoped
public class MyManagedBean implements Serializable {
#EJB(mappedName = "ejbBean")
public MyEjbBean ejbBean;
....
}
EJB bean:
#Singleton(name = "ejbBean")
public class MyEjbBean {
....
}
Page not rendered, error:
javax.naming.NamingException: Could not dereference object [Root exception is javax.naming.NameNotFoundException: ejb not bound]
What am I doing wrong?
JBoss 5 doesn't support #Singleton EJB (added in EJB3.1 spec), you can use the JBoss #Service annotation to create a singleton.
See the instructions here.

Where to close opened clients or use java garbage collection in JSF?

I use JSF portlets with Liferay. In the bean's constructer, I created some objects and also some clients to access some servers. I don't know where should I deconstruct those objects or use garbage collector and also close those clients when I refreshed the page or redirected any other page.
Thanks for helps.
Don't use the constructor. For sure not if you're using CDI. Also for sure don't rely on GC when it comes to cleaning up expensive resources. Just use #PostConstruct and #PreDestroy annotations on the desired methods. The bean management framework will all by itself explicitly call them when the bean scope starts and ends.
public class Bean {
#PostConstruct
public void init() {
// ...
}
#PreDestroy
public void destroy() {
// ...
}
}
This works on both JSF and CDI managed beans. Only when using #ViewScoped in JSF 2.0-2.1, the #PreDestroy isn't guaranteed to be invoked in all circumstances. In case you're using CDI on a Servlet (i.e. non-Portlet) environment, the OmniFaces #ViewScoped solves this problem of JSF 2.0-2.1 #ViewScoped #PreDestroy fail.

Resources