How to use custom Exception in Session Beans? - java

EJB 3.1 Session Bean:
import javax.ejb.*;
public class FooException extends EJBException {
}
#Stateless #Local
public class Foo {
public void bar() throws FooException {
if (/* something wrong */) {
throw new FooException();
}
}
}
Now the test:
import org.junit.*;
public class FooTest {
#Test(expected = FooException.class)
public void testException() {
new InitialContext().lookup("Foo").bar();
}
}
The problem is that EJBException is caught in the test, not FooException. Looks like EJB container looses information about my custom exception type and throws a basic type (EJBException). What is wrong here? (it's OpenEJB 3.1)

First of all, you don't need to use the #Local annotation here. This designates an interface as a local interface or when used at a bean (in your case) can be used to point to a local interface (via the value attribute). Neither case is applicable here. Your code as given will also not compile. lookup("Foo") will return an Object that needs to be casted.
Anyway about the problem, the EJB container doesn't loose any information but wraps your exception in an EJBException. This is because FooException ultimately inherits from RuntimeException. Any such exception is treated by the container as a nonapplication exception and for those the EJB spec defines that they should be wrapped.
In your situation you already extend from EJBException, so it seems like this is a corner case. JBoss AS 6 for instance doesn't do the extra wrapping in this situation, but apparently OpenEJB does.
You can solve this problem by either not letting FooException inherit from EJBException, or by catching the exception in your test, unwrapping it and rethrowing the unwrapped exception.
Since your bar method is declaring that it throws FooException, my guess is that you didn't realize that EJBException is a RuntimeException and thus a nonapplication exception. Why did you let FooException inherrit from EJBException? Did you think this was somehow required, or does this need to server some special purpose?
(as an extra hint, make sure you understand the difference between application and nonapplicaton exceptions with respect to rolling back any transaction and destroying the pooled bean)

Related

Using #Retryable in methods define in spring bean's base class are not retried

I have a spring managed bean of type B. I have #EnableREtry in a #Configuration class. When I use #Retryable on doStuff(), the method gets retried on failure as expected.
But, the method I really want to retry is a method defined in the base class, A. A is a concrete class and not a spring managed bean. the doSomethingElse method doesn't get retried on throwing an exception.
I really want doSomethingElse to be retried, the base class method. However, I'm not sure how to do this. I'm guessing it's because A is a concrete class and not a bean, although it does serve as a base class.
Do I need to use a RetryableTemplate in class A?
public class B extends A {
public void doStuff() {
super.doSomethingElse();
}
}
public class A {
// doesn't actually retry
#Retryable
public void doSomething() {
throws new Exception();
}
}
#Retryable is implemented using Spring AOP.
Only external calls to retryable methods go through the proxy (which invokes the method within a RetryTemplate); internal calls within the class bypass the proxy and therefore are not retried.
You can play some tricks to get a reference to the proxy from the application context and call that, or simply use a RetryTemplate directly within your doStuff() method.

How can a Spring bean detect if it itself has been wrapped in an AOP proxy?

We are using Spring's TransactionInterceptor to set some database partition information using ThreadLocal whenever a DAO method marked with the #Transactional annotation is executed. We need this to be able to route our queries to different database partitions.
This works fine for most DAO methods:
// this causes the invoke method to set a thread-local with the host name of
// the database server the partition is on
#Transactional
public int deleteAll() throws LocalDataException {
The problem is when we need to reference the DAO proxy object itself inside of the DAO. Typically we have to have the caller pass in the proxy-dao:
public Pager<Foo, Long> getPager(FooDao proxyDao) {
This looks like the following in code which is obviously gross.
fooDao.getPager(fooDao);
The problem is that when we are inside of FooDao, the this is not the proxy DAO that we need.
Is there a better mechanism for a bean to discover that it has a proxy wrapper around it? I've looked at the Spring AOPUtils but I see no way to find the proxy for an object. I don't want isAopProxy(...) for example. I've also read the Spring AOP docs but I can't see a solution there unless I implement my own AOP native code which I was hoping to avoid.
I suspect that I might be able to inject the DAO into itself with a ApplicationContextAware utility bean and a setProxyDao(...) method, but that seems like a hack as well. Any other ideas how I can detect the proxy so I can make use of it from within the bean itself? Thanks for any help.
A hacky solution along the lines of what you have suggested, considering that AspectJ compile time or load time weaving will not work for you:
Create an interface along these lines:
public interface ProxyAware<T> {
void setProxy(T proxy);
}
Let your Dao's implement the ProxyAware implementation, now create a BeanPostProcessor with an Ordered interface to run last, along these lines:
public class ProxyInjectingBeanPostProcessor implements BeanPostProcessor, Ordered {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (AopUtils.isAopProxy((bean))){
try {
Object target = ((Advised)bean).getTargetSource().getTarget();
if (target instanceof ProxyAware){
((ProxyAware) target).setProxy(bean);
}
} catch (Exception e) {
// ignore
}
}
return bean;
}
#Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
It is ugly, but works.
There is a handy static utility AopContext.currentProxy() method provided by Spring which returns a proxy to object from which it was called.
Although using it is considered a bad practice, semantically the same method exists in Java EE as well: SessionContext.getBusinessObject().
I wrote few articles about this utility method and various pitfalls: 1, 2, 3.
Use Spring to inject a bean reference into the bean, even the same bean, just as you would for any other bean reference. No special action required.
The presence of such a variable explicitly acknowledges in the class design that the class expects to be proxied in some manner. This is not necessarily a bad thing, as aop can change behavior that breaks the class contract.
The bean reference would typically be for an interface, and that interface could even be a different one for the self-referenced internal methods.
Keep it simple. That way lies madness. :-)
More importantly, be sure that the semantics make sense. The need to do this may be a code smell that the class is mixing in multiple responsibilities best decomposed into separate beans.

EJB3 correlation ID

Now my colleagues work on logging subsystem and they want to bind separate operations, that was initiated from some business method. For example, if method from bean A calls to some method in bean B and then in bean C it will be great to know than business methods in bean B and bean C does some staff for method from bean A. Especially it will be great to know that methods from B and C done some unit of work for concrete call of bean A.
So, the question is how to tie this units of work into something total? Obviously, it is not beautiful to use method arguments for binding!
And also I think that it is time to ask another question, that is close enough to previous one. What if I want to propagate some context information from bean A to another beans, that are called from A? Something like security credentials and security principal? What can I do?
May be questions that I asked is some kind of bad practice?
Looks like a good use case for mdc, available in both Logback and Log4J. Essentially you are attaching some custom value to a thread and all logging messages comming from that thread can attach that value to the message.
I think the best way to implement this in EJB will be an interceptor:
public class MdcInterceptor {
#AroundInvoke
public Object addMdcValue(InvocationContext context) throws Exception {
MDC.put("cid", RandomStringUtils.randomAlphanumeric(16));
try {
return context.proceed();
} finaly {
MDC.remove("cid");
}
}
}
Now all you have to do is add:
%X{user}
to your logging pattern (logback.xml or log4j.xml).
See also
Logging user activity in web app
For general purpose context information you can use TransactionSynchronizationRegistry. It could look something like this:
#Stateless
public class MyBean {
#Resource
TransactionSynchronizationRegistry registry;
#AroundInvoke
public Object setEntryName(InvocationContext ic) throws Exception {
registry.putResource(NAME, "MyBean");
return ic.proceed();
}
}
#Stateless
public class MyBean2 {
#Resource
TransactionSynchronizationRegistry registry;
public void doJob() {
String entryName = (String)registry.getResource(NAME);
...
}
}
I believe it is usually implemented using ThreadLocal variables as normally each transaction maps to a sigle thread in application servers. So if TransactionSynchronizationRegistry is not implemented in your AS (like e.g. in JBoss 4.2.3) or you need lower level tool, you could use ThreadLocal variables directly.
BTW I guess that MDC utilities use the same thing under the covers.

EJB3 Getting at original JDBC Errors

I am using EJB3 on Glassfish using the default TopLink persistance manager. Within a Session Bean, when the persistence manager catches a DB exception, it marks the transaction to be rolled back, and throws an EJBException, in turn wrapping a RollbackException. Now I was expecting to be able to get the original jdbc exception out of the caused by exception of one of these exceptions, but it is not.
It is important that I do retrieve the original exception, as I need to report back to the users what the problem is, and to do this I need to analyse the SQL error codes.
Does anyone know if it is possible to get this information from Toplink? Or whether Hibernate makes it possible?
Thanks,
I had the same issue. I ended up using the AroundInvoke interceptor method , that way you can catch any exception on the server side , and extract whatever info you want to and wrap it to throw your own exception , and set the EjbContext to rollback the transaction.
I can provide you with an example if you don't come right.
Good question, Ant
I know you want to throw a database exception but when it occurs the application, in most of the time, is not able to restore its initial state or it does not know how to recover from it. So it should be handled as a runtime exception. Some problems in database exceptions includes
database connection failure
query is wrong
table or column does not exist
Above you see the application is not be able to restore its initial state. If you think it is possible restore its initial state so you should use a application exception. Client will get the same application exception thrown by your business method. If you want to be able to get the exact exception thrown by your business method you have two choices:
Use a business delegate pattern to access your EJB
As you know, runtime exception is wrapped by a EJBException, so you shold use something like
Let's suppose you have this Stateless session bean
#Stateless
public class BeanImpl implements Bean {
public void doSomething() {
try {
// some code
} catch(SomeException e) {
throw new EJBException(e);
}
}
}
So you wrap your session bean through a business delegate
public class BeamBusinessDelegate implements Bean {
// your stateless session bean goes here
private Bean bean;
public BeamImpl() {
InitialContext i = new InitialContext();
bean = (Bean) i.lookup(<GLOBAL_JNDI_ADDRESS_OR_RELATIVE_ENVIRONMENT_NAMING_CONTEXT_ADDRESS>);
}
public void doSomething() {
try {
bean.doSomething()
} catch(EJBException e) {
throw e.getCause();
}
}
}
Or you can extends EJBException according to your needs
public class DatabaseException extends EJBException {
}
So in your business method
#Stateless
public class BeanImpl implements Bean {
public void doSomething() {
try {
// some code
} catch(SomeException e) {
throw new DatabaseException();
}
}
}
regards,
The only way I've found to do what I want, is to force the manager to write to the db using manager.flush(), and then catch the PersistenceException that that throws. I can then log the database error as I want, and throw an EJBException to force rollback. Leaving the container to do the flush seems to irretrievably lose any useful messages with TopLink.
I have the same question : how to get the SQL error message generated from JPA?
I haven't found the solution either but, I added this line in my persistence.xml
<properties>
<property name="toplink.logging.level" value="FINE" />
</properties>
and now, I can see the sql commands issued.
Reference :
http://www.jairrillo.com/blog/2008/09/04/introduction-to-jpa-part-1-getting-started/

JAX-WS - Map Exceptions to faults

I am using JAX WS to expose a WebService. Some of the operations of this service can generate exceptions. Not internal server exceptions, but rather exceptions that are dependent on the input arguments of the operation invocation.
If I specify that my operation throws a custom Exception, like so:
#WebService
#SOAPBinding(style = Style.RPC, use = Use.LITERAL)
public class MyServiceEndpointImpl implements MyServiceEndpoint {
#WebMethod
public void throwsException throws InvalidInputException;
}
I end up with the following stacktrace when running the application:
com.sun.xml.ws.model.RuntimeModelerException: runtime modeler error: Wrapper class com.mypackage.ws.services.jaxws.InvalidInputExceptionBean is not found. Have you run APT to generate them?
at com.sun.xml.ws.model.RuntimeModeler.getClass(RuntimeModeler.java:285)
at com.sun.xml.ws.model.RuntimeModeler.processExceptions(RuntimeModeler.java:1006)
at com.sun.xml.ws.model.RuntimeModeler.processRpcMethod(RuntimeModeler.java:969)
at com.sun.xml.ws.model.RuntimeModeler.processMethod(RuntimeModeler.java:546)
at com.sun.xml.ws.model.RuntimeModeler.processClass(RuntimeModeler.java:370)
at com.sun.xml.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:256)
at com.sun.xml.ws.server.EndpointFactory.createSEIModel(EndpointFactory.java:322)
at com.sun.xml.ws.server.EndpointFactory.createEndpoint(EndpointFactory.java:188)
at com.sun.xml.ws.api.server.WSEndpoint.create(WSEndpoint.java:467)
at org.jvnet.jax_ws_commons.spring.SpringService.getObject(SpringService.java:333)
at org.jvnet.jax_ws_commons.spring.SpringService.getObject(SpringService.java:45)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport$1.run(FactoryBeanRegistrySupport.java:121)
Adding #XmlRootEntity to InvalidInputException does not solve the problem.
If this is not the recommended way to report faults over web services, then is there a better way? Should my exceptions inherit from RuntimeException and rely on the transport for the error handling (i.e., everything will end up wrapped in a SOAPException)? I was hoping for something like Spring-WS' SoapFaultAnnotationExceptionResolver. Is there something similar at all available for JAX-WS?
Did you try to annotate your exception with #WebFault? Also, do you implement getFaultInfo()?
EDIT: I realize my answer was maybe not detailed enough. As reminded in this thread (for example):
The JAX-WS 2.0 specification demands
that the exception annotated with
#WebFault must have two constructors
and one method [getter to obtain the fault information]:
WrapperException(String message, FaultBean faultInfo)
WrapperException(String message, FaultBean faultInfo, Throwable cause)
FaultBean getFaultInfo()
The WrapperException is replaced by
the name of the exception, and
FaultBean is replaced by the class
name that implements the fault bean.
The fault bean is a Java bean that
contains the information of the fault
and is used by the Web service client
to know the cause for the fault.
This is detailed in section 2.5 Fault of the JAX-WS specification. Does your exception conform to this? Can you post the code?
The OP is right. As per specification 2.1, section 3.7 Service Specific Exception, it is not required to use the #WebFault annotation, JAX-WS can generate the wrapper beans dynamically for exceptions that do not match the pattern described in section 2.5 (just provide a getter for the information you want to be present in the fault). For exceptions that match the pattern described in section 2.5 (i.e. exceptions that have a getFaultInfo method and #WebFault annotation), the FaultBean is used as input to JAXB when mapping the exception to XML Schema.
So the solution suggested above (matching the pattern described in section 2.5) is only a workaround. The generation of wrapper beans should just work for other exceptions. And I don't know why this fails here.
An addition to the answer above. I ended up with this as my InvalidInputException implementation:
#WebFault(faultBean = "com.mypackage.ws.exception.FaultBean")
public class InvalidInputException extends Exception {
private static final long serialVersionUID = 1L;
private FaultBean faultBean;
public InvalidInputException() {
super();
}
public InvalidInputException(String message, FaultBean faultBean, Throwable cause) {
super(message, cause);
this.faultBean = faultBean;
}
public InvalidInputException(String message, FaultBean faultBean) {
super(message);
this.faultBean = faultBean;
}
public FaultBean getFaultInfo() {
return faultBean;
}
}
And FaultBean is just a simple POJO with currently no data at all. Now, according to the JAX-WS specification (see 3.7 Service Specific Exception), it conforms to what is required of an exception annotated with #WebFault, so it will not create a wrapper bean for it, which probably is what was failing.
This is a decent workaround, but it does not explain the error in the question.

Categories