How to access StateContext within an interceptor - spring-statemachine

I am trying to persist state machine when event is sent. To do so, I am using
the following code.
engine.getStateMachineAccessor()
.doWithAllRegions(item -> {
item.addStateMachineInterceptor(new StateMachineInterceptorAdapter<String, String>() {
#Override
public void preStateChange(State state,
Message message,
Transition transition,
StateMachine stateMachine)
{
_Logger.info("In the pre-state change stage");
}
From the documentation, StateContext is only available with preTransition and postTransition events, is there any way to obtain it with preStateChange event?

Related

Spring WebFlux detect client disconnect

Suppose the following #RestController:
#GetMapping("listen")
public Flux<Object> listen() {
return Flux.create(sink -> process(sink));
}
And somewhere
sink.next(new Object());
This code has no information about sink state or completion
Tried using isCanceled, it returns false every time.
Is it possible to detect is FluxSink is still being used by the client?
In spring-webflux if the client close the connection the subscription will be canceled and disposed.
If in the process method you add a callback onCancel and onDispose you will see that.
private <T> void process(final FluxSink<T> sink) {
sink.onCancel(new Disposable() {
#Override
public void dispose() {
System.out.println("Flux Canceled");
}
});
sink.onDispose(new Disposable() {
#Override
public void dispose() {
System.out.println("Flux dispose");
}
});
}
Then send an http request to your endpoint and cancel it before your flux complete. You will see that both callbacks are triggered.
the accepted answer is only work combined with "sever send event", the server send periodical event to client, when the client is disconnected the subscription will be canceled. as the document says https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-codecs-streaming

Event bus Subscribe method called multiple times

I'am new to Vaadin and java web applications in general.
I tried to use event bus from google, this is my setup
Event bus singleton class:
public class Bus {
protected static final EventBus eventBus = new EventBus(); //single instance
public static EventBus getBus() {
return eventBus;
}
}
Place where i post my event:
public class MainMenuElementMain extends HorizontalLayout {
Bus eventbus = new Bus();
public MainMenuElementMain(String sectionTitle) {
ClickedMainMenuElement event = new ClickedMainMenuElement(sectionTitle);
eventbus.getBus().post(event);
}
}
Place where i handle the event:
#Subscribe
public void menuElementClicked (ClickedMainMenuElement event) {
add.(someComponent);
}
Everything is O.K. up to the time when i post the event from other web browser, than i got one of those two errors:
IllegalStateException: Can't move a node from one state tree to another
or
IllegalStateException: Cannot access state in VaadinSession or UI without locking the session.
I did some debugging and it seems that each time I refresh the browser or open new tab, the new instance of #Subscribe is register into the Event buss. In conclusion when i post the event all of the #Subscribe methods, from different sessions are called, which cause the error that i mentioned above.
It seems that my eventBus is a singleton sheared through all the sessions, What would be the best approach to make one instance of Event Buss for one session ?

Custom Event Notifier for apache camel doesn't work for exchange events

I have a spring-boot application that implements a camel routing service. I want to know if the consumers queues are alive or not (because those queues are not in my system). I implemented a Event Notifier to know if the exchange sent event it's triggered or not. But my custom implementation of the Event notifier is not working. I can see in the logs when camel context event is triggered but this is all. No other event is captured by the event notifier.
Thanks.
This is may event notifier class:
#Component
public class MyLoggingSentEventNotifer extends EventNotifierSupport {
private static final Logger logger = LoggerFactory.getLogger(MyLoggingSentEventNotifer.class);
#Override
public void notify(final EventObject event) throws Exception {
if (event instanceof CamelContextStartedEvent) {
}
if (event instanceof ExchangeSentEvent) {
final ExchangeSentEvent sent = (ExchangeSentEvent) event;
log.info("Took {} millis to send to: {}", sent.getTimeTaken(), sent.getEndpoint());
}
if (event instanceof ExchangeCreatedEvent) {
final ExchangeSendingEvent sending = (ExchangeSendingEvent) event;
log.info("Sending to to: {}", sending.getEndpoint());
}
}
#Override
public boolean isEnabled(final EventObject event) {
if (event instanceof CamelContextStartedEvent) {
return true;
}
return false;
}
}
The problem is your isEnabled method where you should filter which events you want to accept. And in your code, you only accept the camel context started event, and therefore you only get that. Instead either just return true for all events, or filter the ones you only want.

Apache Wicket: React on Ajax Request Before Model is Updated

I have a number of Wicket components on a page that use a PropertyModel to reflect properties of some beans. Using AjaxFormComponentUpdatingBehaviors, these components are automatically updated via Ajax when the user changes them.
When properties are changed, the beans I want to edit with my components fire PropertyChangeEvents that should trigger re-renders of certain components that listen to these events (implementing PropertyChangeListener):
Example:
User edits a TextField with a PropertyModel and an AjaxFormComponentUpdatingBehavior
An AJAX request is sent
Wicket dispatches the request to the AjaxFormComponentUpdatingBehavior
The behavior's onEvent updates the PropertyModel (unfortunately, this method is final)
The PropertyModel calls the backing bean's property setter
The backing bean fires and PropertyChangeEvent
Now I want all components listening for changes of the same backing bean to be notified
The behavior calls the abstract onUpdate, but now it's to late, the property change events are already handled.
Since my beans are not serializable, I cannot register the components permanently as event listeners. I either need to register proxy objects that somehow retrieve the component to notify, or register my components temporarily for the scope of the AJAX request.
What I would like to do is to hook into Wickets request cycle after the target page has been loaded but before the Ajax behavior updates the model, that would lead to the PropertyChangeEvent. Here I can register every component as a event listener on their backing beans (addPropertyChangeListener) so that they are notified if they need to be updated.
Then, in onEvent, each component can take measures to update itself using the AjaxRequestTarget if they received a PropertyChangeEvent before.
Finally, in onDetach, the components can unregister from their beans (removePropertyChangeListener).
Unfortunately, I found no built-in way to get a notification "on Ajax request". In my Ajax behavior's onUpdate methods, the model has already been updated and it is too late to register change listeners. I could implement my own behavior, but with the different component options (text fields, choice lists, etc.), this is quite an effort.
Did I miss something?
I don't quite understand exactly what you mean by "components registering as event listeners". Are you talking about registering IRequestCycleListeners?
Either way, perhaps Wicket's inter-component events can help you here. Every component implements the following interface:
public interface IEventSink
{
/**
* Called when an event is sent to this sink
*
* #param event
*/
void onEvent(IEvent<?> event);
}
You could subclass AjaxFormComponentUpdatingBehavior to fire an event after a model is updated like so:
public class AjaxUpdateEvent {
private final AjaxRequestTarget target;
public AjaxUpdateEvent(AjaxRequestTarget target) {
this.target = target;
}
public AjaxRequestTarget getAjaxRequestTarget() {
return target;
}
}
public class BeanModifiedEvent extends AjaxUpdateEvent {
private final Bean bean;
public BeanModifiedEvent(AjaxRequestTarget target, Bean theBean) {
super(target);
}
public Bean getBean() {
return bean;
}
}
public class CustomUpdatingBehavior extends AjaxFormComponentUpdatingBehavior {
protected abstract void onUpdate(AjaxRequestTarget target) {
Bean bean = getFormComponent().getModelObject();
getComponent().send(getComponent().getPage(), Broadcast.BREADTH, new BeanModifiedEvent(target, bean));
}
}
You can then catch the event in the required components and add them to the ajax request:
public class UserDetailsPanel extends Panel {
.....
#Override
public void onEvent(IEvent event) {
if(event.getPayload() instanceof BeanModifiedEvent) {
// if(whatever) to control whether to add or not
AjaxRequestTarget target = ((BeanModifiedEvent) event.getPayload()).getAjaxRequestTarget();
target.add(...);
}
}
Event doc:
17.2, "Wicket events infrastructure" section
18.3, "Built-in AJAX behaviors" section
You can override #getUpdateModel() to return false, then in #onUpdate() do whatever you want before calling getFormComponent().updateModel().
You could be overriding onModelChanging of each component you are using and firing your PropertyChangeEvent there. According to the documentation onModelChanging is called before
the model is changed.
#Override
protected void onModelChanging() {
super.onModelChanging();
oldModelObject = yourComponent.getModelObject();
//fire PropertyChangeEvent
}
This is what I came up with in the end.
I subclassed IContextProvider<AjaxRequestTarget, Page> to create a custom provider for AjaxRequestTarget objects. When an AjaxRequestTarget is requested, I broadcast it to the component tree using Wicket's event mechanism.
public class BroadcastingAjaxRequestTargetProvider implements IContextProvider<AjaxRequestTarget, Page> {
private final IContextProvider<AjaxRequestTarget, Page> parent;
public BroadcastingAjaxRequestTargetProvider(IContextProvider<AjaxRequestTarget, Page> parent) {
this.parent = parent;
}
#Override
public AjaxRequestTarget get(Page page) {
AjaxRequestTarget target = parent.get(page);
page.send(page, Broadcast.BREADTH, new AjaxRequestBegin(target));
return target;
}
}
The class AjaxRequestBegin is just a small payload object encapsulating the AjaxRequestTarget.
I register this provider in my Wicket application's init() method:
setAjaxRequestTargetProvider(new BroadcastingAjaxRequestTargetProvider(getAjaxRequestTargetProvider()));
Now each component gets notified when an AJAX request is handled, before Wicket dispatches it to a component or behavior. A component can override onEvent to register a PropertyChangeListener for the request:
public void onEvent(IEvent<?> event) {
final Object payload = event.getPayload();
if (payload instanceof AjaxRequestBegin) {
final AjaxRequestTarget target = ((AjaxRequestBegin) payload).getTarget()
AjaxPropertyChangeListener listener = new AjaxPropertyChangeListener(target);
target.addListener(listener);
getBean().addPropertyChangeListener(listener);
}
}
private class AjaxPropertyChangeListener implements PropertyChangeListener, AjaxRequestTarget.IListener {
private final AjaxRequestTarget target;
public AjaxPropertyChangeListener(AjaxRequestTarget target) {
this.target = target;
}
#Override
public void propertyChange(PropertyChangeEvent event) {
target.add(MyComponent.this);
}
#Override
public void onBeforeRespond(Map<String, Component> map, AjaxRequestTarget target) {
}
#Override
public void onAfterRespond(Map<String, Component> map, IJavaScriptResponse response) {
getBean().removePropertyChangeListener(this);
}
}
Note that AjaxPropertyChangeListener also implements AjaxRequestTarget.IListener to unregister itself after the AJAX request has been completed.

GwtEvent does not get dispatched

I have an application that uses EventBus for dispatching Application wide events. For some reason if I call one event and then try to register handler immediately before firing the second event it does not get dispatched. Is there any other way to dynamically register handlers on event ? Please see the code below:
MyEntry.java
package com.example.eventbus.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
public class MyEntry
implements EntryPoint {
SimpleEventBus bus;
#Override
public void onModuleLoad() {
bus = new SimpleEventBus();
fireEvent1();
}
private void fireEvent1(){
bus.addHandler(MyEvent1.TYPE,new MyEvent1.Handler() {
#Override
public void onEvent1(MyEvent1 event) {
RootPanel.get().add(new Label("Event1"));
fireEvent2();
}
});
bus.fireEvent(new MyEvent1());
}
private void fireEvent2(){
bus.addHandler(MyEvent2.TYPE,new MyEvent2.Handler() {
#Override
public void onEvent2(MyEvent2 event) {
RootPanel.get().add(new Label("Event2")); //!!!!!This line is not being called
}
});
bus.fireEvent(new MyEvent2());
}
}
MyEvent1.java
package com.example.eventbus.client;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
public class MyEvent1 extends GwtEvent<MyEvent1.Handler>{
public static Type<MyEvent1.Handler> TYPE=new Type<MyEvent1.Handler>();
#Override
public com.google.gwt.event.shared.GwtEvent.Type<Handler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(Handler handler) {
System.out.println("dispatch Event1");
handler.onEvent1(this);
}
public interface Handler extends EventHandler{
public void onEvent1(MyEvent1 event);
}
}
MyEvent2.java
package com.example.eventbus.client;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
public class MyEvent2 extends GwtEvent<MyEvent2.Handler>{
public static Type<MyEvent2.Handler> TYPE=new Type<MyEvent2.Handler>();
#Override
public com.google.gwt.event.shared.GwtEvent.Type<Handler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(Handler handler) {
System.out.println("dispatch Event2"); //!!!! This line is never called
handler.onEvent2(this);
}
public interface Handler extends EventHandler{
public void onEvent2(MyEvent2 event);
}
}
The issue is that while an event bus is firing events, it queues up any added or removed handler, and deals with them when it is finished. The idea is that if you only start listening to something while another event is still going off, then you are not interested for this round of events, but for the next round. The same thing happens when removing a handler - you will still hear about events that are still in the process of happening, but after the event bus is finished firing, it will deal with removal.
Try changing your code to wire up both handlers before firing anything, then try firing one event to the other.
Let me suggest to take a try to a new feature in gwtquery called 'custom events'.
We have introduced the new events mechanism during the recent GWT.create conferences, take a look to this slide (use arrows to move between slides).
You can attach custom events to any element in the DOM tree, widgets, and the window element.
Then you can trigger the event from any point in your code and every handler with this custom event name will be executed.
The main goal of the gQuery approach apart from being simpler, is that it performs significantly better than gwt eventbus, since the native browser selects in a low-level way which handlers to execute instead of using javascript to loop over a list, and execute handlers sequentially.
You might want to check out GWTP #ProxyEvent:
So when should you use #ProxyEvent? Basically, you use it every time that an event should have the ability to “wake up” your presenter. That is, whenever the presenter should be notified of an event even before it is first instantiated.

Resources