Event not working in Message Driven Bean - events

I'm trying to generate and handle an event when my MDB receives a message. Here is what I'm doing:
public class MDBBooks implements MessageListener {
#Inject
private Event<Update> messageReceived;
public MDBLibri() {
}
#Override
public void onMessage(Message message) {
System.out.println("Message received");
try {
Update u = message.getBody(Update.class);
messageReceived.fire(u);
if(u != null){
... stuff
}
} catch (JMSException ex) {
System.out.println("JMSException: " + ex.getMessage());
}
}
public void eventHandler(#Observes Update up) {
System.out.println("There was an update");
}
}
But it just does not work, the string "There was an update" it's not printed in the glassfish console. I can't really tell what's the problem, my textbook does it the same way pretty much. I'm assuming the event fires fine, but the event handler isn't notified.

You are correct that the observer method does not get notified. In fact, CDI doesn't even know it exists. The reason is that in CDI, message-driven beans are non-contextual objects. To simplify, they are not considered CDI beans, but you can still inject into them and intercept them.
Now, for CDI to recognize an observer method, you have to place it in a managed bean or a session bean. Quoting the spec:
An observer method is a non-abstract method of a managed bean class or session bean class (or of an extension, as defined in Container lifecycle events).
So a solution for you would be to place your observer method in another class, which is either a managed bean or a session bean.

Related

Spring Transaction Doesn't Rollback

We have a Spring Transaction rollback issues, where rollback doesn't seems to be working.
Within my service layer method which is annotated with #Transactional I call three different DAOImpl classes to insert 3 records. The middle insert do a get from a 4th table to populate a description field but this get failed. I expect the first insert to rollback but it doesn't seems to be happening.
Few Points:
The 'Get' method throws a Runtime Exception
We are using org.springframework.jdbc.datasource.DataSourceTransactionManager and MySQL datasource defined in applicationContext.xml. Beans are created in Beans.xml which is imported into ApplicationContext.xml
No #Transactional annotation in DAO layer
We have used <tx:annotation-driven transaction-manager="transactionManager"/> again in applicationContext.xml
We are using Spring 3.1
UPDATE:
Code snippets....
Service Class- This is somthing similar to what I have .... I tested with and without #Autowired. The transaction enable method is called within the service class.
public class CustomerService {
//#Autowired
CustomerOrderDAO customerOrderDAOImpl;
//#Autowired
CustomerItemDAO customerItemDAOImpl;
//#Autowired
CustomerPromotionDAO customerPromotionDAOImpl;
//#Autowired
PromotionDAO promotionDAOImpl;
//other variables
public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder) {
try {
saveOrderDetails(customerOrder);
.....
return customerOrder;
} catch (Exception e) //TO-DO catch proper exception
{
//Send error response
.......
return customerOrder;
}
}
#Transactional
public void saveOrderDetails(CustomerOrder customerOrder) throws Exception {
customerOrderDAOImpl.create(customerOrder);
....
while (promotionsIterator.hasNext()) {
customerPromotion.setPromotionName(promotionDAOImpl.getName(customerOrder.getPromotionId));
customerPromotionDAOImpl.create(customerPromotion);
}
......
while (customerItemIterator.hasNext()) {
customerItemDAOImpl.create(customerItem);
}
}
}
Any idea?
Thanks.
The default behaviour of #Transactional is that transactional behaviour is added with a proxy around the object (the CustomerService in your example). From the reference docs (scroll down):
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with #Transactional.
In your example, an external call to the handlingIncomingOrders() passes through the proxy and hits the target object (an instance of the CustomerService). However, the subsequent call to saveOrderDetails() is a normal method call inside the target object, thus the transactional behaviour in the proxy is never invoked. However, if the saveOrderDetails() was called from another class, you will find that the transactional behaviour will work as expected.
The solution in your case would be calling saveOrderDetails(customerOrder); as proxyBean.saveOrderDetails(customerOrder); Where proxybean is the Object on whichhandleIncomingOrders` is being called.
If CustomerService is singleton (Defualt scope) it can be as simple as adding below code to the Service class. (adding a self reference as autowired)
//#Autowired
CustomerService customerService; // As this is injected its a proxy
and in the Method use it as
public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder) {
try {
customerService.saveOrderDetails(customerOrder);
.....
return customerOrder;
} catch (Exception e) //TO-DO catch proper exception
{
//Send error response
.......
return customerOrder;
}
}
If its scope is Prototype the one of possible simple solution will be as follows.
public CustomerOrder handleIncomingOrders(CustomerOrder customerOrder, CustomerService customerService) {
try {
customerService.saveOrderDetails(customerOrder);
.....
return customerOrder;
} catch (Exception e) //TO-DO catch proper exception
{
//Send error response
.......
return customerOrder;
}
}
And where you are calling handleIncomingOrders use changes suggested in below code.
bean.handleIncomingOrders(customerOrder); //Suppose this is old code
Change it to
bean.handleIncomingOrders(customerOrder, bean);// THough it appears as we are sending reference to `THIS` as parameter whcihc can be unnecessary, in case of `Proxy`while inside your method `this` and `Passed reference` will point to different Obejects.

what the usage of method start() in AbstractApplicationContext

I'm a spring user. and I start to read the source code of spring.
when I read AbstractApplicationContext, I found there's one method start(), I found that the method doesn't be called when ApplicationContext is initialized.
My questions:
1)what the usage of the method? according to the word's(start) meaning, I think it should be called before the ApplicationContext can work. but it doesn't.
2)how can I listen the event which applicationContext starting working? after reading the code, I found the method will publish ContextStartedEvent. but if I just initialize the context, the context still can work and don't publish event.I can't listen the event to track the start of applicationcontext.
The start method is part of the Lifecycle interface, which is called as part of the application startup process.
If you want to be notified when the context is starting you should declare a bean that implements the Lifecycle interface.
public class org.example.MyLifecycle implements Lifecycle {
private boolean started = false;
public boolean isRunning() {
return started;
}
public void start() {
System.err.println("MyLifecycle starting");
started = true;
}
public void stop() {
System.err.println("MyLifecycle stopping");
started = false;
}
}
Then
<bean class="org.example.MyLifecycle"/>
This is all handled, by default, by DefaultLifecycleProcessor unless there's a bean in the context called lifecycleProcessor which implements the LifecycleProcessor interface

Spring Remoting HTTP invoker - exception handling

I'm using Spring's 'HTTP Invoker' remoting solution to expose DAOs to many different applications, but have all database access in a single server.
This works well, but if the server throws, say, a HibernateSystemException, Spring serializes that and sends it over the wire back to the client. That doesn't work because the client doesn't (and shouldn't) have HibernateSystemException in its classpath.
Might there be a way to have Spring Remoting wrap my exception in something that I specify that would be common between client and server to avoid issues like this?
I know that I could do that in my server code by wrapping everything the DAO does in a try/catch, but that's admittedly sloppy.
Thanks,
Roy
I ran into this issue as well; I am exposing a service via HTTP Invoker that accesses a database using Spring 3.1, JPA 2, and Hibernate as the JPA provider.
To work around the problem, I wrote a custom Interceptor and an exception called WrappedException. The interceptor catches exceptions thrown by the service and converts the exceptions and causes to WrappedException using reflection and setters. Assuming the client has the WrappedException on its class path, the stack trace and original exception class names are visible to the client.
This relaxes the need for the client to have Spring DAO on its class path and as far as I can tell, no original stack trace information is lost in the translation.
Interceptor
public class ServiceExceptionTranslatorInterceptor implements MethodInterceptor, Serializable {
private static final long serialVersionUID = 1L;
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
try {
return invocation.proceed();
} catch (Throwable e) {
throw translateException(e);
}
}
static RuntimeException translateException(Throwable e) {
WrappedException serviceException = new WrappedException();
try {
serviceException.setStackTrace(e.getStackTrace());
serviceException.setMessage(e.getClass().getName() +
": " + e.getMessage());
getField(Throwable.class, "detailMessage").set(serviceException,
e.getMessage());
Throwable cause = e.getCause();
if (cause != null) {
getField(Throwable.class, "cause").set(serviceException,
translateException(cause));
}
} catch (IllegalArgumentException e1) {
// Should never happen, ServiceException is an instance of Throwable
} catch (IllegalAccessException e2) {
// Should never happen, we've set the fields to accessible
} catch (NoSuchFieldException e3) {
// Should never happen, we know 'detailMessage' and 'cause' are
// valid fields
}
return serviceException;
}
static Field getField(Class<?> clazz, String fieldName) throws NoSuchFieldException {
Field f = clazz.getDeclaredField(fieldName);
if (!f.isAccessible()) {
f.setAccessible(true);
}
return f;
}
}
Exception
public class WrappedException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String message = null;
public void setMessage(String message) {
this.message = message;
}
#Override
public String toString() {
return message;
}
}
Bean Wiring
<bean id="exceptionTranslatorInterceptor" class="com.YOURCOMPANY.interceptor.ServiceExceptionTranslatorInterceptor"/>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="YOUR_SERVICE" />
<property name="order" value="1" />
<property name="interceptorNames">
<list>
<value>exceptionTranslatorInterceptor</value>
</list>
</property>
</bean>
I can understand you don't want your clients to have HibernateSystemException in their classpath, but I'd argue they should, if you're using HTTPInvoker appropriately. It's not designed to be a service facade / interface layer: all it's meant to do is let you run Java methods on a remote JVM, using HTTP instead of RMI.
So if you really don't want the clients to have a dependency on Hibernate, your try/catch block is the way to go. (I'd argue against that though, since it'll make debugging a pain: your stack trace will now be divided between the client and the server).
I haven't used it myself but you could try the org.springframework.remoting.support.RemoteExporter.setInterceptors(Object[]) method to add an aspect to catch that particular exception in just one place rather than adding try/catches all over the place.
I would argue a try/catch in a Facade layer in front of your DAOs is exactly what you want, in order to gain full control over the exceptions you return. I agree it initially feels ugly, but it's a vital layer between client and DAO, in my opinion.
You might even return a OperationStatus object of some sort, rather than use void return types, to convey both outcome (worked, didn't) and error message, for store-data API calls.
I used a solution similar to N1H4L's but with AspectJ.
First I made all the exceptions I want the client to be aware of to extend the class BusinessException (which in my case is a very simple subclass of RuntimeException in the jar with the service interface and DTOs).
Since I don't want the client to know much about the internals of the service I just say "Internal server error".
package com.myproduct.myservicepackage;
import com.myproduct.BusinessException;
import org.aspectj.lang.*;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class InternalServerErrorExceptionAspect {
#Pointcut("execution(public * com.myproduct.myservicepackage..*Service.*(..))")
public void publicServiceMethod() {}
#Around("publicServiceMethod()")
public Object hideNonBusinessExceptions(ProceedingJoinPoint jp) throws Throwable {
try {
return jp.proceed();
} catch (BusinessException e) {
throw e;
} catch (RuntimeException e) {
e.printStackTrace();
throw new RuntimeException("Internal server error.")
}
}
}
Here's the BusinessException class:
package com.myproduct.BusinessException;
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 8644864737766737258L;
public BusinessException(String msg) {
super(msg);
}
}
I was using AspectJ to wrap exception but it does not work for exception that occur in Spring proxy, e.g. annotation #Transactional when the connection to the database fails.
However, the method setInterceptor on RmiServiceExporter works perfectly.

Is transactional #observes working for fired events on JBoss AS 7?

In order to use events only listened if a transaction succeeds or fails, I'm following the given doc about transactional observers :
http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html_single/#d0e4075
... but cannot manage to make my code work on JBoss AS7.
Here's my EJB:
#LocalBean
#Stateful
#TransactionAttribute(TransactionAttributeType.NEVER)
public class MyController
{
#Inject
private transient Event<MyEvent> myEventLauncher;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void save()
{
myEventLauncher.fire(new MyEvent());
}
#AfterCompletion
protected void afterSave(boolean isCommitted)
{
// do stuff
}
}
And here my basic listener:
public class MyHandler
{
protected void listenMyEvent(#Observes(during=TransactionPhase.AFTER_SUCCESS) MyEvent event)
{
// do stuff
}
protected void listenMyEvent2(#Observes(during=TransactionPhase.AFTER_FAILURE) MyEvent event)
{
// do stuff
}
}
I can say I'm in a transaction when the event is fired, because the afterSave method of the EJB is called. Alas, the methods listenMyEvent and listenMyEvent2 are always called both, like if I was not in a transactional context.
I tried the same code on GlassFish 3 and it perfectly works, so I guess there is a problem with JBoss AS 7, but I cannot find any bug report about it.
Well, as my current tests made me think that transactional observers are not working in JBoss AS 7, I managed to do a workaround I gave here for people who are interested.
First, we need qualifier annotations: Immediate, AfterFailure and AfterSuccess.
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD, ElementType.PARAMETER })
public #interface AfterFailure
{}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD, ElementType.PARAMETER })
public #interface AfterSuccess
{}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD, ElementType.PARAMETER })
public #interface Immediate
{}
Also, three basic AnnotationLiteral to create in runtime instances of this three annotations.
Then, we need a encapsulator for our true events, that I named SpecialEvent.
public class SpecialEvent
{
private Object event; // the real event you want
public SpecialEvent(Object event)
{
super();
this.event = event;
}
public Object getEvent()
{
return event;
}
}
And at last, an observer for this special event and an interceptor for classes where you want to fire this kind of events (full explanation below).
#RequestScoped
public class SpecialEventObserver
{
#Inject
private Event<Object> anyEventFirer; // firer for real events
private List<Object> events; // queued events
public SpecialEventObserver()
{
events = new ArrayList<Object>();
}
// remove all queued events
public void reset()
{
this.events.clear();
}
public void fireAfterFailureEvents() throws Exception
{
this.fireAllEventsOnce(new AfterFailureLiteral());
}
public void fireAfterSuccessEvents() throws Exception
{
this.fireAllEventsOnce(new AfterSuccessLiteral());
}
protected void listenSpecialEvent(#Observes SpecialEvent specialEvent)
{
Object event = specialEvent.getEvent();
this.events.add(event);
this.fireEvent(event, new ImmediateLiteral());
}
protected void fireAllEventsOnce(Annotation qualifier) throws Exception
{
try
{
for (Object event : this.events)
{
this.fireEvent(event, qualifier);
}
}
catch (Exception e)
{
throw e;
}
finally
{
this.events.clear();
}
}
protected void fireEvent(Object event, Annotation qualifier)
{
Event eventFirer = anyEventFirer.select(event.getClass(), qualifier);
eventFirer.fire(event);
}
}
#Interceptor
#LocalInterception
public class MyInterceptor implements Serializable
{
#Inject
private SpecialEventObserver specialEventObserver;
#AroundInvoke
public Object intercept(InvocationContext ic) throws Exception
{
specialEventObserver.reset();
try
{
// call the real method
Object proceedResult = ic.proceed();
// real method succeeded, fire successful events
specialEventObserver.fireAfterSuccessEvents();
return proceedResult;
}
catch (Exception e)
{
// real method failed, fire failed events
specialEventObserver.fireAfterFailureEvents();
throw e;
}
}
}
The mechanism is quite simple:
When you want to fire an event, fire a SpecialEvent that hold the true event.
The SpecialEventObserver will catch any SpecialEvent and will immediately fire your own event with an Immediate qualifier. It will also queue the events for the after completion part.
At the end of your own method call (ic.proceed in the interceptor), MyInterceptor will ask the SpecialEventObserver either to fire again all events with a AfterFailure qualifier or a AfterSuccess qualifier, depending of the success of your method.
In place of #Observes(during=...), your own observers have to observe events with the right qualifier, like #Observes #Immediate, #Observes #AfterFailure or #Observes #AfterSuccess.
The behavior is not exactly the one that provides the native #Observes(during=...). The after completion part is not based on the transaction state, but on your own method call success:
In JaveEE6, transactional observers on after success or after failure phases must be immediately called if you're not in a transaction, like a IN_PROGRESS would do.
In this workaround, observers on after success or after failure phases will always be called at the end of the method, and only if it succeeded or failed.
This works with version 7.1.0.Final which is supposedly (-> with Jboss you never know) fully Java EE compliant. Also your bean is not thread-safe as it uses list instead of a concurrent queue.
Your observer methods need REQUIRES_NEW, as stated here :
http://www.seamframework.org/Documentation/WhyIsThereNoActiveTransactionInMySFSBTransactionalObserver

Get all existing session beans from all users in Spring

Is there a way to get all existing session beans managed by Spring at runtime? Getting them for the current user is easy.
Any suggestions?
Thanks,
XLR
I don't do Spring, but in normal JSF/JSP/Servlet you would grab HttpSessionBindingListener for this. Basically you need to give the session scoped bean a static List<Bean> property and implement the interface accordingly that it updates the static list in the valueBound() and valueUnbound() methods.
You can find a detailed code example in this answer.
Here is a solution I came up with that utilizes Spring:
I make a normal Spring singleton bean called SessionBeanHolder.
This bean holds a list of my session beans.
When a user logs in, I add the session bean to my SessionBeanHolder.
When referring to session beans in Spring, you are actually referring to proxies.
So the key thing to making this work was to fetch the underlying bean to add to the SessionBeanHolder.
Below is the sample code:
Note: My session bean is called SessionInfo.
#Scope(value="singleton")
#Component
public class SessionBeanHolder {
static Set<SessionInfo> beans;
public SessionBeanHolder() {
beans = new HashSet<SessionInfo>();
}
public Collection<SessionInfo> getBeans() {
return beans;
}
public void addBean(SessionInfo bean) {
try {
this.beans.add(removeProxyFromBean(bean));
} catch (Exception e) {
e.printStackTrace();
}
}
// Fetch the underlying bean that the proxy refers to
private SessionInfo removeProxyFromBean(SessionInfo proxiedBean) {
if (proxiedBean instanceof Advised) {
try {
return (SessionInfo) ((Advised) proxiedBean).getTargetSource().getTarget();
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
return proxiedBean;
}
}
}
Naturally, whenever you want to add session bean or fetch a list of all beans, just autowire the SessionBeanHolder and use its methods.
#Autowired
SessionBeanHolder sessionBeanHolder;

Resources