Spring State Machine Error Handling not working - java

I did all the setup for error handling
#PostConstruct
public void addStateMachineInterceptor() {
stateMachine.getStateMachineAccessor().withRegion().addStateMachineInterceptor(interceptor);
stateMachine.getStateMachineAccessor().doWithRegion(errorinterceptor);
}
created interceptor to handle error:
#Service
public class OrderStateMachineFunction<T> implements StateMachineFunction<StateMachineAccess<String, String>> {
#Override
public void apply(StateMachineAccess<String, String> stringStringStateMachineAccess) {
stringStringStateMachineAccess.addStateMachineInterceptor(
new StateMachineInterceptorAdapter<String, String>() {
#Override
public Exception stateMachineError(StateMachine<String, String> stateMachine,
Exception exception) {
// return null indicating handled error
return exception;
}
});
}
}
But I can't see the call going into OrderStateMachineFunction, when we throw the exception from the action.
And after that state machine behave some wired way, like it stops calling preStateChange method after this.stateMachine.sendEvent(eventData);. It seems state machine breaks down after you throw the exception from the action.
#Service
public class OrderStateMachineInterceptor extends StateMachineInterceptorAdapter {
#Override
public void preStateChange(State newState, Message message, Transition transition, StateMachine stateMachine) {
System.out.println("Manish");
}
}
After trying few bit, I have seen that if I comment the resetStateMachine, it works as expected, but without that I am not able to inform the currentstate to state machine:
public boolean fireEvent(Object data, String previousState, String event) {
Message<String> eventData = MessageBuilder.withPayload(event)
.setHeader(DATA_KEY, data)
.build();
this.stateMachine.stop();
// this.stateMachine
// .getStateMachineAccessor()
// .withRegion()
// .resetStateMachine(new DefaultStateMachineContext(previousState, event, eventData.getHeaders(), null));
this.stateMachine.start();
return this.stateMachine.sendEvent(eventData);
}

Not sure if you still need this. But I bumped into similar issue. I wanted to propagate exception from state machine to the caller. I implemented StateMachineInterceptor. And inside the state machine transition functions I am setting:
try
{
..
}
catch (WhateverException e)
{
stateMachine.setStateMachineError(e);
throw e;
}
Then inside the interceptor's stateMachineError method, I have added the Exception in the extendedState map:
public Exception stateMachineError(StateMachine<States, Events> stateMachine, Exception exception)
{
stateMachine.getExtendedState().getVariables().put("ERROR", exception);
logger.error("StateMachineError", exception);
return exception;
}
Inside resetStateMachine I have added the interceptor to the statemachine.
a.addStateMachineInterceptor(new LoggingStateMachineInterceptor());
Then when I am calling the sendEvent method, I am doing this:
if (stateMachine.hasStateMachineError())
{
throw (Exception) svtStateMachine.getExtendedState().getVariables().get("ERROR");
}
This is returning the WhateverException right to the caller. Which in my case is a RestController.

The approach I'm taking here is combining the extended state to store errors with an error action.
If an expected exception happens in your action and any class inside of it, I include it in the extended state context
context.getExtendedState().getVariables().put("error", MyBussinessException);
then, on my error action (configured like this)
.withExternal()
.source(State.INIT)
.target(State.STARTED)
.action(action, errorAction)
.event(Events.INIT)
Outside machine context, I always check if that field is present or not, and translate it to proper response code.
If any exception is thrown from action, error action will be triggered. There you can check known errors (and let them bubble up), or include a new errors (if that was unexpected)
public class ErrorAction implements Action<States, Events> {
#Override
public void execute(StateContext<States, Events> context) {
if(!context.getExtendedState().getVariables().containsKey("error")
context.getExtendedState().getVariables().put("error", new GenericException());
}
}

Related

Using Vert.x handle errors thrown in request middleware

Say I have some middleware and an error is raised:
public class JWTHandler implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
throw new Error("How can I capture this error and send a response.")
ctx.next();
}
}
How can I capture it using some error-handling middleware? Here is a global error handler but it can't reference any request/response pair.
vertx.createHttpServer()
.exceptionHandler(ctx -> {
// I cannot access the request that may have caused the error here
log.error("In the exception handler.");
log.error(ctx.getCause());
})
the only thing I can guess, is something like this:
public class ErrorHandler implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
try{
ctx.next();
}
catch(Exception e){
ctx.response().end("We messed up.");
}
}
}
but I doubt that idea is right? What's the right way to do this?
perhaps one or both of these is sufficient?
router.route().failureHandler(ctx -> {
ctx.response().end("We failed here!");
});
router.route().last().handler(ctx -> {
ctx.response()
.setStatusCode(404)
.end("404 - route/resource could not be found.");
});
I think, the correct approach would be to use the ctx.fail(), when throwing an exception
public class JWTHandler implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
ctx.fail(new Error("How can I capture this error and send a response.");
}
}
And then you can add a failerHandler and access to the Exception with ctx.failure()
router.route().failureHandler(ctx -> {
ctx.response().end(
ctx.failure().getMessage()
);
});
EDIT:
the failureHandler also catches exceptions that are thrown like you did:
public class JWTHandler implements Handler<RoutingContext> {
public void handle(RoutingContext ctx) {
throw new Error("How can I capture this error and send a response.")
ctx.next();
}
}

Custom Exception Dispatcher in Spring Boot Application for response logic

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

Vaadin and Spring with Touchkit. servlet and annotation based?

I have a fully working spring and vaadin application based off spring boot. The application class has now been modified to create a custom servlet so I can use both touchkit and spring within the project as such.
I have been following this git project to perform this:git project example
public class SmartenderApplication {
public static void main(String[] args) {
SpringApplication.run(SmartenderApplication.class, args);
}
#Bean
public VaadinServlet vaadinServlet() {
return new SpringAwareTouchKitServlet();
}}
I modified the custom servlet to follow the vaadin docs for using a UI provider to choose between the touchkit UI and the browswer fallback UI as so
public class SpringAwareTouchKitServlet extends SpringVaadinServlet {
TouchKitSettings touchKitSettings;
MyUIProvider prov = new MyUIProvider();
#Override
protected void servletInitialized() throws ServletException {
super.servletInitialized();
getService().addSessionInitListener(
new SessionInitListener() {
#Override
public void sessionInit(SessionInitEvent event)
throws ServiceException {
event.getSession().addUIProvider(prov);
}
});
touchKitSettings = new TouchKitSettings(getService());
}
}
class MyUIProvider extends UIProvider {
#Override
public Class<? extends UI>
getUIClass(UIClassSelectionEvent event) {
String ua = event.getRequest()
.getHeader("user-agent").toLowerCase();
if ( ua.toLowerCase().contains("ios")) {
return myTouchkitUI.class;
} else {
return myUI.class;
}
}
}
My application works when I do not call this section of code to choose a UI provider. But it will always go to a touchkit UI. :
getService().addSessionInitListener(
new SessionInitListener() {
#Override
public void sessionInit(SessionInitEvent event)
throws ServiceException {
event.getSession().addUIProvider(prov);
}
});
My issue is that although it will choose between which UI class to return as soon as it begins to progress through the chosen UI code it passes back null objects that were originally autowired through spring. Seeing as this works when i dont choose a UI and just goes for touchkit, im assuming it must be somewhere in my UI provider choice code thats stopping the Spring functionality from allowing my classes to autowire, etc?
Well, the UIProvider is supposed to manage UI instances. Furthermore, since you're using Spring (Boot or not) it should retrieve beans from the Spring context instead of creating the instances itself when one is necessary:
UIProvider / DefaultUIProvider:
public UI createInstance(UICreateEvent event) {
try {
return event.getUIClass().newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Could not instantiate UI class", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Could not access UI class", e);
}
}
Thus, I'd say that instead of extending the simple UIProvider (or rather the DefaultUIProvider) you should extend the SpringUIProvider, which retrieves instances from your app's Spring context, so the automagic will begin to happen again.
SpringUIProvider:
#Override
public UI createInstance(UICreateEvent event) {
final Class<UIID> key = UIID.class;
final UIID identifier = new UIID(event);
CurrentInstance.set(key, identifier);
try {
logger.debug(
"Creating a new UI bean of class [{}] with identifier [{}]",
event.getUIClass().getCanonicalName(), identifier);
return webApplicationContext.getBean(event.getUIClass());
} finally {
CurrentInstance.set(key, null);
}
}

How to catch exception in Join point which was thrown from #Around

Following up with this comment of my previous question. I'm trying to throw an exception from the #Around advice, and catch it within the callee class and/or method. But I'm getting this error:
Stacktraces
java.lang.Exception: User not authorized
com.company.aspect.AuthorizeUserAspect.isAuthorized(AuthorizeUserAspect.java:77)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:616)
...
The Aspect code is:
#Aspect
public class AuthorizeUserAspect {
#AuthoWired
private UserService service;
#Pointcut("#annotation(module)")
public void authorizeBeforeExecution(AuthorizeUser module) {}
#Around(value = "authorizeBeforeExecution(module)", argNames="module")
public Object isAuthorized(ProceddingJoinPoint jp, AuthorizeUser module) throws Throwable {
// Check if the user has permission or not
service.checkUser();
if ( /* User has NOT permission */ ) {
throw new MyCustomException("User not authorized"); // => this is line 77
}
return jp.proceed();
}
}
and the Struts's based UI action code is:
#Component
public class DashboardAction extends ActionSupport {
#Override
#AuthorizeUser
public String execute() {
...
}
private void showAccessDenied() {
...
}
}
The question is How or Where I can catch that exception to execute showAccessDenied()?
To handle uncaught exceptions like MyCustomException you need to define a global exception handler in Struts 2. Please check this guide: http://struts.apache.org/2.3.4.1/docs/exception-handling.html
For user interface I'd recommend writing a short code for catching any uncaught exceptions.
class EventQueueProxy extends EventQueue {
#Override
protected void dispatchEvent(AWTEvent newEvent) {
try {
super.dispatchEvent(newEvent);
} catch (Throwable t) {
String message = t.getMessage();
if (message == null || message.length() == 0) {
message = "Fatal: " + t.getClass();
}
JOptionPane.showMessageDialog(null, message, "Unhandled Exception Caught!", JOptionPane.ERROR_MESSAGE);
}
}
}
And then in the ui class:
public static void main(String args[]) {
EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue();
queue.push(new EventQueueProxy());
//your code goes here...
}
Note, it will show the dialog window with an error information each time uncaught exception appears. This is just the suggestion for your ui, for the particular case of your ploblem, do use try for firing method(s) that authorizes a user and catch for firing method(s) that should be executed if the user is not authorized. in such case authorization method should throw an exception if an authorization fails. Then the error will not be printed but the particular method will be fired instead.
That's what I'd add to your code:
#Component
public class DashboardAction extends ActionSupport {
#Override
try {
#AuthorizeUser
public String execute() {
...
}
} catch (Exception e) {
private void showAccessDenied() {
...
}
}
}

Detecting when a handler couldn't be started when embedding Jetty

I'm embedding Jetty in a similar manner as described here. When the RequestLogHandler can't open the specified logfile, it throws an exception which is unfortunately caught by org.eclipse.jetty.server.Server and swallowed (but logged first, at least). This means that there's no obvious way for me to tell if the log handler was started correctly.
Is there a way that I'm missing to detect when a handler couldn't start?
This idea is based on the implementation of WebAppContext where you can use WebAppContext.getUnavailableException() to determine whether the context was initialized successfully.
Simply replace the default implementation of Server and Context with your own:
public static class MyContext extends Context {
private Exception _exception;
#Override
protected void doStart() throws Exception {
try {
super.doStart();
} catch (final Exception e) {
_exception = e;
}
}
#Override
protected void doStop() throws Exception {
try {
super.doStop();
} finally {
_exception = null;
}
}
public Exception getException() {
return _exception;
}
}
public static class MyServer extends Server implements InitializingBean {
public void afterPropertiesSet() throws Exception {
start();
for (final Handler h : getHandlers()) {
if (h instanceof MyContext) {
final MyContext c = (MyContext) h;
if (c.getException() != null) {
throw new RuntimeException("failed to init context " + c.getDisplayName(),
c.getException());
}
}
}
}
}
In your beans.xml, simply replace org.mortbay.jetty.Server (and remove init-method="start") and org.mortbay.jetty.servlet.Context with your own implementations.
This code is for Jetty 6 though (as is the example you linked to), as that's what I have around. I didn't test it though, but it's pretty much the same as we are successfully using in conjunction with WebAppContext. In order to extend this to RequestLogHandler, you could either do the same for just any handler you are using or create a decorator to wrap any handler. You may want to look at org.mortbay.jetty.handler.HandlerWrapper for this purpose.
How about modifying the jetty code? You could add some simple println statements in strategic places in the RequestLogHandler which would indicate to you whether or not the handler was started.

Categories

Resources