I'm working on EJB client + server, and I wonder, how to deal with server data errors on client. Should I check return value on client or catch an Exception? Example, that use return value logic:
//server bean method
public int create(MyObj obj) {
int PKID = someDataService.create(obj);
return PKID;
}
//client
if(!(MyBean.create(obj) > 0)) {
showMessage("Can't create MyObj");
}
Example with exceptions:
//server bean method
public void create(MyObj obj) {
int PKID = someDataService.create(obj);
if(!(id > 0)) {
//only EJBExceptions will be delivered to client
throw new EJBException(new MyDataException());
}
}
//client
try {
MyBean.create(obj);
}
catch(EJBException e) {
if(e.getCause().getClass.equals(MyDataException.class)) {
showMessage("Can't create MyObj");
}
else {
showMessage("Some boring error occurred");
}
}
I know, that return value checking instead of exceptions looks like coding in C, but all this EJB thing confuses me. Which is the better way?
Throw exception from your method
public void create(MyObj obj) throws MyDataException
and annotate your custom exception with ApplicationException
#javax.ejb.ApplicationException
public class MyDataException extends Exception
{
Related
I am implementing a SOAP service in Mule ESB version 3.8 using the HTTP and CXF component. Please see attached image for the flow design.
The Mule flow is :
HTTP and CXF component exposes the web service which gives sum of two integers. The object send in request is :
public class AddValues{
private int a;
private int b;
public setA(int a)
{
this.a =a;
}
public getA()
{
return a;
}
public setB(int b)
{
this.b =b;
}
public getB()
{
return b;
}
}
Save the SOAP action using a variable.
Based on the SOAP Action route the Flow control.
Using a JAVA transformer to receive the payload and throw Custom Web fault exception as follows:
public class AddValuesBusinessLogic extends AbstractMessageTransformer
{
#Override
public Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException {
MuleMessage muleMessage = message;
AddValues addValues = (AddValues) muleMessage.getPayload();
if (addValues.getA() == null || addValues.getB() == null ) {
//Make an AddValueException object
throw new Exception("Add value exception");
}
return null;
}
}
But i am getting the error "Surround with try/catch"
My question is if I surround and handle the exception, how am I going to send the SOAP Fault to end user?
Can someone please suggest what is the best way to send a custom SOAP Fault from JAVA Transformer in Mule ESB?
I found a solution using TransformerException and CXF OutFaultInterceptor.
My approach is as follows:
Write a custom transformer class inside which add the validation rules. For example, if I want to throw Error for Integer a or b being null, I will add a Custom Transformer AddValuesBusinessLogic.class with the following code:
public class AddValuesBusinessLogic extends AbstractMessageTransformer
{
#Override
public Object transformMessage(MuleMessage message, String outputEncoding) throws
TransformerException
{
MuleMessage muleMessage = message;
AddValues addValues = (AddValues) muleMessage.getPayload();
if (addValues.getA() == null || addValues.getB() == null ) {
//Make an AddValueException object
throw new TransformerException(this,new AddValueException("BAD REQUEST"));
}
return "ALL OK";}
This exception will then propagate to CXF where I am writing an OutFaultInterceptor like follows:
public class AddValuesFaultInterceptor extends AbstractSoapInterceptor {
private static final Logger logger = LoggerFactory.getLogger(AddValuesFaultInterceptor.class);
public AddValuesFaultInterceptor() {
super(Phase.MARSHAL);
}
public void handleMessage(SoapMessage soapMessage) throws Fault {
Fault fault = (Fault) soapMessage.getContent(Exception.class);
if (fault.getCause() instanceof org.mule.api.transformer.TransformerMessagingException) {
Element detail = fault.getOrCreateDetail();
Element errorDetail = detail.getOwnerDocument().createElement("addValuesError");
Element errorCode = errorDetail.getOwnerDocument().createElement("errorCode");
Element message = errorDetail.getOwnerDocument().createElement("message");
errorCode.setTextContent("400");
message.setTextContent("BAD REQUEST");
errorDetail.appendChild(errorCode);
errorDetail.appendChild(message);
detail.appendChild(errorDetail);
}
}
private Throwable getOriginalCause(Throwable t) {
if (t instanceof ComponentException && t.getCause() != null) {
return t.getCause();
} else {
return t;
}
}
}
Now when I make a call using either SOAPUI or jaxws client, I get the custom fault exception in the SOAP response.
To extract the values of errorCode and errorMessage in JAXWS client I am doing the following in the catch block of try-catch:
catch (com.sun.xml.ws.fault.ServerSOAPFaultException soapFaultException) {
javax.xml.soap.SOAPFault fault = soapFaultException.getFault(); // <Fault> node
javax.xml.soap.Detail detail = fault.getDetail(); // <detail> node
java.util.Iterator detailEntries = detail.getDetailEntries(); // nodes under <detail>'
while(detailEntries.hasNext()) {
javax.xml.soap.DetailEntry detailEntry = (DetailEntry) detailEntries.next();
System.out.println(detailEntry.getFirstChild().getTextContent());
System.out.println(detailEntry.getLastChild().getTextContent());
}
}
This is working for me as of now.
However I will request suggestionsto improve on this workaound or if there are any better solutions.
Thanks everyone.
You should create your own SOAP Fault (plain Java String) and return it as a message. If you want, you can also create a transformer and put it in your catch-exception-strategy like this:
#Override
public Object transformMessage(MuleMessage message, String outputEncoding)
throws TransformerException {
String exceptionMessage = message.getExceptionPayload().getException().getCause().getMessage();
String outputMessage = "<soap:Fault xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"> " +
" <faultcode>soap:Server</faultcode> " +
"<faultstring>" + exceptionMessage + "</faultstring>" +
"</soap:Fault>";
return outputMessage;
}
Mule always expects Exceptions to be encapsulated in a TransformerException, so you should throw a new TransformerException setting your own Exception as the cause.
I have a Java EE application with dozens of web services using the same pattern:
public Response myWebService1() {
try {
// do something different depending on the web service called
} catch (MyCustomException e1) {
return Response.status(409).build();
} catch (UnauthorizedException e2) {
return Response.status(401).build();
} catch (Exception e3) {
return Response.status(500).build();
}
}
Is that possible to factorize this piece of code?
If this is a JAX-RS environment, see Tunaki's answer, handling this is specifically catered for and wonderfully simple.
If not:
You can have a functional interface accepting a function that can throw exceptions and returns a Response:
#FunctionalInterface
public interface Responder {
Response handleRequest() throws Exception;
}
(As Dici points out, you could make that a generic ThrowingSupplier or similar, since you're allowing it to throw Exception.)
Then have a helper method accepting an instance of it:
private static Response respond(Responder responder) {
try {
return responder.handleRequest();
} catch (MyCustomException e1) {
return Response.status(409).build();
} catch (UnauthorizedException e2) {
return Response.status(401).build();
} catch (Exception e3) {
return Response.status(500).build();
}
}
...and use it via a lambda:
public Response myWebService1() {
return respond(() -> {
// Do stuff here, return a Response or throw / allow throws on error
});
}
Since this is in a JAX-RS context, there is a much better way, that does not rely on catching a lot of different exceptions: use an ExceptionMapper. This is a built-in mechanism of JAX-RS 1.0 that translates an exception type into a proper Response object to send to the client.
In your case, you could have the following classes defined once in your application:
#Provider
public class UnauthorizedExceptionMapper implements ExceptionMapper<UnauthorizedException> {
public Response toResponse(UnauthorizedException e) {
return Response.status(401).build();
}
}
#Provider
public class MyCustomExceptionMapper implements ExceptionMapper<MyCustomException> {
public Response toResponse(MyCustomException e) {
return Response.status(409).build();
}
}
#Provider
public class CatchAllExceptionMapper implements ExceptionMapper<Exception> {
public Response toResponse(Exception e) {
return Response.status(500).build();
}
}
The #Provider annotation tells the JAX-RS runtime to discover this class when scanning. This makes sure that, wherever in your code, if a MyCustomException is thrown (and not explicitly catched), a 409 response will be returned. The code in your application would simply become:
public Response myWebService1() {
// do something, and don't catch anything; just care about the happy path
}
The exception hierarchy is correctly taken into account. If the application code throws a MyCustomExceptionMapper, JAX-RS will look for an exception mapper registered with that type, and will go up the super class if it can't find one: this way, there can be a catch-all exception mapper handling every other case.
If all methods handle exceptions the same way, you can extract the exception handling to an external method :
public static Response exceptionHandler (Exception exc)
{
if (exc instanceof MyCustomException) {
return Response.status(409).build();
} else if (exc instanceof UnauthorizedException) {
return Response.status(401).build();
} else {
return Response.status(500).build();
}
}
public Response myWebService1() {
try {
// do something different depending on the web service called
} catch (Exception exc) {
return exceptionHandler(exc);
}
}
Sure, that is possible. We have a solution that looks like:
} catch (Exception exception) {
exceptionConverter.convertAndThrow(exception);
}
to unify re-throwing of exceptions based on the exception caught.
So that exception converter is the one central place where we "switch" over the exception type and do what needs to be done. Of course, the central element here is: all your classes need the exact same handling for the incoming exceptions.
We even go one step further and allow a wild mix of potential "input causes", but we also have extensive unit tests to ensure that the conversion always gives the expected result.
Please note: my answer is just about refactoring those "catch" cascade. You can still turn to TJs solution; but keep in mind: that approach adds a certain bit of complexity by introducing that Runnable aspect.
#T.J.Crowder's response is perfect. But for those who can't use Java 8, this is how to implement it with earlier version of Java:
The Responder interface:
public interface Responder {
Response handleRequest() throws Exception;
}
The helper method:
private static Response respond(Responder responder) {
try {
return responder.handleRequest();
} catch (MyCustomException e1) {
return Response.status(409).build();
} catch (UnauthorizedException e2) {
return Response.status(401).build();
} catch (Exception e3) {
return Response.status(500).build();
}
}
With an anonymous class instead of a lambda expression:
Response response = respond(new Responder() {
#Override
public Response handleRequest() throws Exception {
...
return Response.ok().build();
}
});
I have a Spring Boot application that has the following approximate structure:
project
Api
ApiImpl
Application
Api is an interface that looks like this:
public interface Api {
public String methodOne(...) throws ExceptionOne, ExceptionTwo, ExceptionThree;
...
public int methodN(...) throws ExceptionOne, ExceptionThree, ExceptionFour;
}
ApiImpls is the request controller (in reality there is a second layer, but this should suffice for this example). There, I do something like the following right now:
#Controller
public class ApiImpl {
public String methodOne(...) {
try {
// do stuff that can yield an exception
}
catch(ExceptionOne e) {
// set proper response code and return values
}
catch(ExceptionTwo e) {
// set proper response code and return values
}
catch(ExceptionThree e) {
// set proper response code and return values
}
}
}
Basically, this behaviour yields a lot of repetition (might as well name my exceptions D, R, and Y...), but is otherwise very suited to handling the internal application logic.
My question is: How can I implement a custom Exception Dispatcher that would handle this in Java? Ideally, I would want something like this answer here, but unfortunately simply throwing the current exception like in that C++ code is not possible in Java, as far as I know. For brevity, what I would like to accomplish is something like the following:
#Controller
public class ApiImpl {
public String methodOne(...) {
try {
// do stuff that can yield an exception
}
catch(ExceptionOne e) {
handle()
}
}
private void handle() { // maybe Throwable or Exception subclass as parameter
// handle the correct exception type, set correct response code, etc.
}
}
Are there any good approaches to doing this so as to minimize code repetition?
Here is a preliminary attempt I tried to get this working:
public class Thrower {
public Thrower(int e) throws ExceptionOne, ExceptionTwo, ExceptionThree {
if(e == 0) {
throw new ExceptionOne();
}
if(e == 1) {
throw new ExceptionTwo();
}
if(e == 2) {
throw new ExceptionThree();
}
}
}
class ExceptionOne extends Exception {}
class ExceptionTwo extends Exception {}
class ExceptionThree extends Exception {}
public class ExceptionHandler {
private void handle(Exception ex) throws Exception {
try {
throw ex;
}
catch(ExceptionOne e) {
e.printStackTrace();
System.out.println("Exception one");
}
catch(ExceptionTwo e) {
e.printStackTrace();
System.out.println("Exception two");
}
catch(ExceptionThree e) {
e.printStackTrace();
System.out.println("Exception three");
}
}
public void causesException(int which) throws Throwable {
try {
Thrower t = new Thrower(which);
}
catch(Exception e) {
handle(e);
}
}
public static void main(String[] args) throws Throwable {
ExceptionHandler eh = new ExceptionHandler();
eh.causesException(0);
eh.causesException(1);
eh.causesException(2);
}
}
This works as expected, and I can handle the different exception types as needed (shown here using a constructor, but the principle would be the same). However, this feels extremely clunky.
If you are looking for globally handling all Controller Layer exceptions (in Spring MVC architecture), you can do that at one place for all controllers (option1 below) by using #ExceptionHandler methods which is a ControllerAdvice from Spring.
Option(1): Configure Exceptions in Separate Class
#ControllerAdvice
class MyProjectExceptionHandler {
#ExceptionHandler(value = ExceptionOne.class)
public R exceptionOne(ExceptionOne exe) {
//set proper response code and return values
}
#ExceptionHandler(value = ExceptionTwo.class)
public R exceptionTwo(ExceptionTwo exe) {
//set proper response code and return values
}
}
Option(2): Configure Exceptions in Controller Class itself
If you are looking for handling the exceptions within the Controller class itself, then you can do that as below:
#Controller
public class ApiImpl {
public String methodOne(...) {
}
#ExceptionHandler(ExceptionOne.class)
public R exceptionTwo(ExceptionOne exe) {
//set proper response code and return values
}
//other exceptions
}
You can look more on this at here
I would like to annotate some of my test cases with KnownFault - which would do pretty much what expectedException does plus some magic using YouTrack's REST API. I would also like to have an IntermittentFailure attribute which would mean that I'm aware that the test might occasionally fail with [exception] [message] but I wouldn't want this to block the rest of my build chain.
After some research I found that my test class should implement IHookable, then I could have something like this:
#Override
public void run(IHookCallBack callBack, ITestResult result) {
callBack.runTestMethod(result);
if (result.getThrowable().getCause() instanceof IllegalArgumentException){
System.out.println("This is expected.");
result.setThrowable(null);
}
else{
System.out.println("Unexpected exception");
}
}
The problem with this is the actual implementation of invokeHookable:
final Throwable[] error = new Throwable[1];
IHookCallBack callback = new IHookCallBack() {
#Override
public void runTestMethod(ITestResult tr) {
try {
invokeMethod(thisMethod, testInstance, parameters);
} catch (Throwable t) {
error[0] = t;
tr.setThrowable(t); // make Throwable available to IHookable
}
}
#Override
public Object[] getParameters() {
return parameters;
}
};
hookable.run(callback, testResult);
if (error[0] != null) {
throw error[0];
}
Unfortunately that last line means that my test case is going to throw an exception no matter what as the error array is completely out of my hands in the run method.
So, what would be the proper way of intercepting an exception and handling it the way I want to?
What you are trying to do is really interesting. You should try to propose changes on https://github.com/cbeust/testng/pull/
But maybe IHookable is not the best listener you can use. Did you try IInvokedMethodListener?
void afterInvocation(IInvokedMethod method, ITestResult result) {
if (result.getThrowable().getCause() instanceof IllegalArgumentException) {
System.out.println("This is expected.");
result.setThrowable(null);
result.setStatus(SUCCESS); // If you want to change the status
} else {
System.out.println("Unexpected exception");
}
}
I have a MessageBean which reads from a Queue we'll name MainQ.
If the execution of the onMessage code throws a user-based Exception with a type we'll name UserException I want to catch this and put this message on a separate Queue named UserErrorQ.
If the exception is not of this type, the Exception is thrown on to be handled by the DMQ.
Here is my issue:
in my catch block I attempt, through a ErrorQueueHandler, to put this new message on the UserErrorQ. This results in an error when I attempt to connect to the connectionFactory to send the message to the UserErrorQ.
Apparently creating a new connection to a QueueConnectionFactory(javax.jms.ConnectionFactory) is causing problems
Error:
com.sun.messaging.jms.JMSException: MQRA:DCF:allocation failure:createConnection:Error in allocating a connection. Cause: javax.transaction.RollbackException
at com.sun.messaging.jms.ra.DirectConnectionFactory._allocateConnection(DirectConnectionFactory.java:548)
at com.sun.messaging.jms.ra.DirectConnectionFactory.createConnection(DirectConnectionFactory.java:265)
at com.sun.messaging.jms.ra.DirectConnectionFactory.createConnection(DirectConnectionFactory.java:244)`
MessageBean:
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void onMessage(Message message) {
try{
.
.
}catch(Exception e){
if(isUserExceptionWrappedInException(e){
errorQueueHandler.sendToErrorQueue(message);
}
}
}
private boolean isUserExceptionWrappedInException(Throwable t) {
if (t == null)
return false;
else if (t instanceof UserException)
return true;
else
return isUserExceptionWrappedInException(t.getCause());
}
ErrorQueueHandler:
public void sendToErrorQueue(Message message) {
try {
createConnection();
send((TextMessage)message);
} finally {
closeConnection();
}
}
private void createConnection() throws Exception {
try {
connection = connectionfactory.createConnection();
connection.start();
} catch (JMSException e) {
String msg = "Error while attempting to initialize connection to jms destination " + ERROR_QUEUE;
throw new OperationalException(msg, e, OperationalExceptionType.APPLIKASJONSTJENER);
}
}
As mentioned, the error occurs when attempting to make the connection. Anyone have a fix for this?
So, I have figured out the answer to my own question.
The reason for the connectionException was that the ErrorQueueHandler was not an EJB, but rather injected via CDI. There are no new instantiations allowed within a rollback state because the container discards the bean instance, which is why it failed. My REQUIRES_NEW annotation was also ignored as this belongs to the javax api, which will not affect a CDI injected bean.
Here are a few things to note:
Make sure the EJB has either no constructors, or public ones. The modifiers are important as the container needs these to be correct for it to instantiate the EJB.
There are a few problems with this approach.
As I am attempting to write the message to a separate error queue instead of the DMQ, I will have to consume the message and not throw the error on afterwards. Because the MDB is in a rollback state, the JMS spec clearly states that this will cause the message to be redelivered. What you will experience is that after writing to you custom errorQueue, the message will bounce right back to the queue and you now have an infinite loop.
Luckily i also have a solution:
The main issue here is controlling your transactions. For this scenario, i need 3 transactions:
One transaction for the MDB so that it is able to acknowledge the message event though i have a RuntimeException.
One transaction for the logic of the onMessage method so that i am able to do a rollback when i get an exception, but also still be able to write to the ErrorQueue.
One transaction for connecting and writing to the ErrorQueue while in a rollback state.
Code:
MessageBean:
#EJB
QueueService queueService;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void onMessage(Message message) {
try{
queueService.processMessageInNewTrasaction(message);
}catch(Exception e){
throw e;
}
}
QueueService:
import javax.jms.Message;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#Stateless
public class QueueService {
#EJB
ErrorQueueHandler errorQueueHandler;
public void processMessageInNewTransaction(Message message){
try {
.
.
} catch(Exception e) {
if(isUserExceptionWrappedInException(e)
errorQueueHandler.sendToErrorQueue(message);
}
}
private boolean isUserExceptionWrappedInException(Throwable t) {
if (t == null)
return false;
else if (t instanceof UserException)
return true;
else
return isUserExceptionWrappedInException(t.getCause());
}
}
ErrorQueueHandler:
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#Stateless
public class ErrorQueueHandler{
public void sendToErrorQueue(Message message){
.
.
}
}
useful resource: http://weblogic-wonders.com/weblogic/2011/01/10/working-with-jms-and-the-standard-issues-in-jms/