CDI WELD #ConversationScoped #Stateful EJB conversation.end() & #Remove SFSB - ejb

currently i am trying to remove a ConversationScoped Stateful Session Bean (SFSB). The ConversationScope is managed by the CDI Container and the lifecycle of the SFSB is managed by the EJB Container. Is this correct?
In my Controller i'm trying to end the conversation by calling a method of the SFSB and to call the #Remove annotated method to destroy the SFSB.
The conversation can be end without any problems but i am not able to destroy the SFSB.
A Code example from Weld Reference Guide (WELD Conversation Scope):
#ConversationScoped #Stateful
public class OrderBuilder {
private Order order;
private #Inject Conversation conversation;
private #PersistenceContext(type = EXTENDED) EntityManager em;
#Produces public Order getOrder() {
return order;
}
public Order createOrder() {
order = new Order();
conversation.begin();
return order;
}
public void addLineItem(Product product, int quantity) {
order.add(new LineItem(product, quantity));
}
public void saveOrder(Order order) {
em.persist(order);
conversation.end();
}
#Remove
public void destroy() {}
}
The controller:
#Named
#SessionScoped
public class TestController implements Serializable{
#Inject
private OrderBuilder orderBuilder;
...
public String checkout(Order order){
orderBuilder.saveOrder(order);
orderBuilder.destroy();
return "success";
}
}
After i have called testController.checkout(order), i'am getting this exception:
javax.servlet.ServletException:
java.lang.reflect.InvocationTargetException
javax.faces.webapp.FacesServlet.service(FacesServlet.java:321)
org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:67)
root cause
javax.faces.el.EvaluationException:
java.lang.reflect.InvocationTargetException
javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:98)
com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:98)
javax.faces.component.UICommand.broadcast(UICommand.java:311)
javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:781)
javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1246)
com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:77)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97)
com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:114)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:308)
org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:67)
Any ideas?
THX

You should end the CDI conversation and CDI will call the #Remove method.
Have a look in Weld documentation :
"
Stateful session beans may define a remove method, annotated #Remove, that is used by the application to indicate that an instance should be destroyed. However, for a contextual instance of the bean—an instance under the control of CDI—this method may only be called by the application if the bean has scope #Dependent. For beans with other scopes, the application must let the container destroy the bean.
"

JSF 1.2 or 2.0 does not support expression like methods with parameter
obj.method(parameter)
JSF supoorts only method without parameter like
obj.method()
Seam 2,3 build in supports this kind of expreesions but if you are using only weld (CDI support of seam, core of seam) without other seam jars, you can not have this ability.
But it is possible to give this kind of ability to JSF.
Adding this to jar project you can use methods with parameters. If you are using maven u can use code below or. Download jars manually in lib folder.
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>el-impl</artifactId>
<version>2.2</version>
</dependency>
Additionally, I tested it with tomcat worked fine, but in jetty some conflicts happen with the other jars. May be it is about my project.
Add this to web xml
<context-param>
<param-name>com.sun.faces.expressionFactory</param-name>
<param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>

Related

Run a code when the war is deployed [duplicate]

I need to get some configuration and connect to external resources/objects/systems somewhere and store it in application scope.
I can see two ways to setup my application:
Overriding the init() in the existing servlets and required code there and keeping all constructed objects inside that same servlet.
Having some kind of an initialisation servlet and using its init() to do the work. Then storing created objects in ServletContext to share it with my other servlets.
Which out of above is better approach? Is there any better way to share objects between servlets? Calling them directly from one another or so...?
None of both is the better approach. Servlets are intended to listen on HTTP events (HTTP requests), not on deployment events (startup/shutdown).
CDI/EJB unavailable? Use ServletContextListener
#WebListener
public class Config implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
// Do stuff during webapp's startup.
}
public void contextDestroyed(ServletContextEvent event) {
// Do stuff during webapp's shutdown.
}
}
If you're not on Servlet 3.0 yet and can't upgrade (it would be about time because Servlet 3.0 was introduced more than a decade ago), and thus can't use #WebListener annotation, then you need to manually register it in /WEB-INF/web.xml like below:
<listener>
<listener-class>com.example.Config</listener-class>
</listener>
To store and obtain objects in the application scope (so that all servlets can access them), use ServletContext#setAttribute() and #getAttribute().
Here's an example which lets the listener store itself in the application scope:
public void contextInitialized(ServletContextEvent event) {
event.getServletContext().setAttribute("config", this);
// ...
}
and then obtain it in a servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
Config config = (Config) getServletContext().getAttribute("config");
// ...
}
It's also available in JSP EL by ${config}. So you could make it a simple bean as well.
CDI available? Use #Observes on ApplicationScoped.class
import jakarta.enterprise.context.ApplicationScoped; // And thus NOT e.g. jakarta.faces.bean.ApplicationScoped
#ApplicationScoped
public class Config {
public void init(#Observes #Initialized(ApplicationScoped.class) ServletContext context) {
// Do stuff during webapp's startup.
}
public void destroy(#Observes #Destroyed(ApplicationScoped.class) ServletContext context) {
// Do stuff during webapp's shutdown.
}
}
This is available in a servlet via #Inject. Make it if necessary also #Named so it's available via #{config} in EL as well.
Noted should be that this is new since CDI 1.1. If you're still on CDI 1.0 and can't upgrade, then pick another approach.
In case you're curious how to install CDI on a non-JEE server such as Tomcat, head to: How to install and use CDI on Tomcat?
EJB available? Consider #Startup#Singleton
#Startup
#Singleton
public class Config {
#PostConstruct
public void init() {
// Do stuff during webapp's startup.
}
#PreDestroy
public void destroy() {
// Do stuff during webapp's shutdown.
}
}
This is available in a servlet via #EJB. The difference with other approaches is that it's by default transactional and in case of #Singleton also read/write locked. So if you would ever need to inject a random EJB (e.g. #Stateless) into a #WebListener or an #ApplicationScoped then you could basically as good merge both into a single #Startup #Singleton.
See also:
How to run a background task in a servlet based web application?
ServletContainerInitializer vs ServletContextListener
How do I force an application-scoped bean to instantiate at application startup?

EJB stateless - Private members initialisation

I'm new to EJB and I'm facing my first problem. I'm trying to use an #Schedule method contained in a Stateless EJB. I'd like this method to use a private member variable which would be set at bean creation:
Here's a short example:
#Singleton
#LocalBean
#Startup
public class Starter {
#PostActivate
private void postActivate() {
ScheduleEJB scheduleEjb = new ScheduleEJB("Hello");
}
}
And the schedule bean:
#Stateless
#LocalBean
public class ScheduleEJB {
private String message;
public ScheduleEJB() {
super();
}
public ScheduleEJB(String message) {
super();
this.message= message;
}
#Schedule(second="*/3", minute="*", hour="*", dayOfMonth="*", dayOfWeek="*", month="*", year="*")
private void printMsg() {
System.out.println("MESSAGE : " + message);
}
}
The problem is that my "message" variable is always null when printed in the printMsg() method... What's the best way to achieve this?
Thanks for your help !
You're mixing few things here.
The #PostActivate annotation is to be used on Stateful Session Beans (SFSB), and you use it on the singleton. I guess that you mean the #PostConstruct method which applies to every bean which lifecycle is managed by the container.
You're using a constructor from your EJB. You cannot do:
ScheduleEJB scheduleEjb = new ScheduleEJB("Hello");
as it creates just an instance of this class. It's not an EJB - the container didn't create it, so this class does not have any EJB nature yet.
That's the whole point of dependency injection - you just define what you want and the container is responsible for providing you with an appropriate instance of the resource.
The Stateless Bean (SLSB) is not intented to hold the state. The SFSB is. Even if you would set the message in one SLSB method (i.e. in some ScheduleEJB#setMessage(String) method) than you need to remember that the EJB's are pooled. You don't have any guarantee that the next time you invoke a method on the ScheduleEJB you will get to the same instance.
In your case it would be the easies solution just to add the #Schedule method to your singleton class. Than you can define the variable of your choice in the #PostConstruct method. You can be sure that there is only one Singleton instance per JVM, so your variable will be visible in the Schedule annotated method of the same class.
HTH.

SessionContext.getBusinessObject() in EJB3 & JNDI lookup

In EJB2, one needed to use getEJBBusinessObject() method in a EJB to pass reference to itself when calling another (local/remote) bean.
Does the same apply for EJB3?
e.g.
#Stateless
public class MyBean implements MyBeanLocal {
#Resource private SessionContext sessionContext;
public void myMethod() {
OtherBeanLocal otherBean = ...; // getting reference to other local EJB.
MyBeanLocal myBean = sessionContext.getBusinessObject(MyBeanLocal.class);
b.aMethod(myBean);
}
// Edit: calling myMethodTwo() from inside of myMethodOne()
public void myMethodOne() {
MyBeanLocal myBean = sessionContext.getBusinessObject(MyBeanLocal.class);
myBean.myMethodTwo();
}
public void myMethodTwo() {
...
}
...
}
Also, if I fetch my local bean using getBusinessObject() method, is it the same as if I use common JNDI lookup?
I've tested both approach, and both work, but I'm not sure if bean object is processed the same way by the container.
Edit:
Is fetching the reference to ejb itself, when calling myMethodTwo() from inside myMethodOne() of the same ejb, in EJB3, still needed? Is it allowed to call methods inside the same ejb through this reference?
How will this address transactions, if I decide to use some?
Yes, the same applies to EJB 3. Yes, getBusinessObject is the EJB 3 analog to getEJBObject (or getEJBLocalObject). All of those methods return a proxy for the current bean object. For stateless session beans, this is basically the same as looking up through JNDI, though it's likely to perform better since it avoids JNDI overhead.

Using special auto start servlet to initialize on startup and share application data

I need to get some configuration and connect to external resources/objects/systems somewhere and store it in application scope.
I can see two ways to setup my application:
Overriding the init() in the existing servlets and required code there and keeping all constructed objects inside that same servlet.
Having some kind of an initialisation servlet and using its init() to do the work. Then storing created objects in ServletContext to share it with my other servlets.
Which out of above is better approach? Is there any better way to share objects between servlets? Calling them directly from one another or so...?
None of both is the better approach. Servlets are intended to listen on HTTP events (HTTP requests), not on deployment events (startup/shutdown).
CDI/EJB unavailable? Use ServletContextListener
#WebListener
public class Config implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
// Do stuff during webapp's startup.
}
public void contextDestroyed(ServletContextEvent event) {
// Do stuff during webapp's shutdown.
}
}
If you're not on Servlet 3.0 yet and can't upgrade (it would be about time because Servlet 3.0 was introduced more than a decade ago), and thus can't use #WebListener annotation, then you need to manually register it in /WEB-INF/web.xml like below:
<listener>
<listener-class>com.example.Config</listener-class>
</listener>
To store and obtain objects in the application scope (so that all servlets can access them), use ServletContext#setAttribute() and #getAttribute().
Here's an example which lets the listener store itself in the application scope:
public void contextInitialized(ServletContextEvent event) {
event.getServletContext().setAttribute("config", this);
// ...
}
and then obtain it in a servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
Config config = (Config) getServletContext().getAttribute("config");
// ...
}
It's also available in JSP EL by ${config}. So you could make it a simple bean as well.
CDI available? Use #Observes on ApplicationScoped.class
import jakarta.enterprise.context.ApplicationScoped; // And thus NOT e.g. jakarta.faces.bean.ApplicationScoped
#ApplicationScoped
public class Config {
public void init(#Observes #Initialized(ApplicationScoped.class) ServletContext context) {
// Do stuff during webapp's startup.
}
public void destroy(#Observes #Destroyed(ApplicationScoped.class) ServletContext context) {
// Do stuff during webapp's shutdown.
}
}
This is available in a servlet via #Inject. Make it if necessary also #Named so it's available via #{config} in EL as well.
Noted should be that this is new since CDI 1.1. If you're still on CDI 1.0 and can't upgrade, then pick another approach.
In case you're curious how to install CDI on a non-JEE server such as Tomcat, head to: How to install and use CDI on Tomcat?
EJB available? Consider #Startup#Singleton
#Startup
#Singleton
public class Config {
#PostConstruct
public void init() {
// Do stuff during webapp's startup.
}
#PreDestroy
public void destroy() {
// Do stuff during webapp's shutdown.
}
}
This is available in a servlet via #EJB. The difference with other approaches is that it's by default transactional and in case of #Singleton also read/write locked. So if you would ever need to inject a random EJB (e.g. #Stateless) into a #WebListener or an #ApplicationScoped then you could basically as good merge both into a single #Startup #Singleton.
See also:
How to run a background task in a servlet based web application?
ServletContainerInitializer vs ServletContextListener
How do I force an application-scoped bean to instantiate at application startup?

AspectJ AOP not working as expected

I am working on AspectJ AOP implementation on spring MVC application. I have written Aspect java class where I am trying to intercept join points for all the methods of one of the packages say com.xyz.services. But AOP always failed to interecept the methods of that package. Aspect is defined as follows -
#Pointcut("execution(* com.xyz.services..*.*(..))")
public void logBefore() {
}
#Before("logBefore()")
public void logHere(JoinPoint joinPoint) {
System.out.println("In logHere ....");
logger.info("logBefore is running ....");
logger.info("hijacked ::::" + joinPoint.getSignature().getName());
logger.info("joinPoint.getSignature().getDeclaringTypeName() ::::"
+ joinPoint.getSignature().getDeclaringTypeName());
logger.info("joinPoint.getSignature().getModifiers() ::::"
+ joinPoint.getSignature().getModifiers());
logger.info("******************************************************");
}
I have enabled AOP in application-context.xml as follows -
<aop:aspectj-autoproxy proxy-target-class="true">
<aop:include name='loggingAspect' />
</aop:aspectj-autoproxy>
When ever I am calling webservice the methods in the com.xyz.services get called but the Aspect method never get called.
I tried with different pointcuts but the aspect code never did not execute.
#Pointcut("execution(public * com.xyz.services.ManagerServiceImpl.*(..))")
public void logBefore() {
System.out.println("In Logbefore");}
#Pointcut("execution(public * com.xyz.services.*.*(..))")
public void logBefore() {
System.out.println("In Logbefore");
}
I have added cglib dependency on pom.xml to enable cglib based proxies.
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
Can anyone help me out why this aspects are not working as expected?
have you configured correctly the class with the annotation ?
#EnableAspectJAutoProxy(proxyTargetClass = true)

Resources