Storing Spring State machine for an object - spring-statemachine

I am new to Spring State machine,however i have gone through the examples.How should one attach Spring state to an instance of an Class.Should it be stored as an attribute of type String in the class.Also how to make the object store the state

Related

Is InvalidStateStoreException possible when state store is obtained from ProcessorContext?

When attempting to obtain a local state store from KafkaStreams it's possible to get InvalidStateStoreException exception if the local KafkaStreams instance is not yet ready or the state store was just migrated to another instance (re-balancing).
Let's say we have DSL topology which includes local state store added by addStateStore and some process or transform (KStream:process or KStream::transform).
Below are my questions:
Could InvalidStateStoreException exception be thrown when local state store is obtained from ProcessorContext context inside Processor::init or Transformer::init, i.e.
KeyValueStore<ByteString, User> userStore =
(KeyValueStore<ByteString, User>) context.getStateStore("store_name");
We store the reference to KeyValueStore<ByteString, User> userStore and use it later to modify the userStore inside Punctuator::punctuate. Should we worry about getting InvalidStateStoreException exception on any put/get/delete operations with this store?
Could InvalidStateStoreException exception be thrown when local state store is obtained from ProcessorContext context inside Processor::init or Transformer::init, i.e.
No. init() will not be called before the store is ready. Thus, an InvalidStateStoreException will never occur.
We store the reference to KeyValueStore userStore and use it later to modify the userStore inside Punctuator::punctuate. Should we worry about getting InvalidStateStoreException exception on any put/get/delete operations with this store?
No. You can safely read/write the store. An InvalidStateStoreException will never occur. punctuate() is executed by the same thread then process() and it's ensured that the store is ready when punctuate() is called.

Hibernate uses old closed SessionImpl instead of given SessionImpl

I have a problem with Hibernate Enverse (Version 5.2.0-Final).
Context:
I'm auditing some entities with some lazy relations. I have a jsf-page that loads one version of one entity with all relations of that version. That works fine. So now I have a page that shows a revision of the entity with all relations of that revision. On this page I can open a fieldset, that triggers an AJAX. In this request we reattach all relations by calling entityManager.merge(entity) to be able to fetch the lazy relations in this fieldset. (The EntityManager is RequestScoped)
The Problem:
The AJAX is a new request. The server calls entityManager.merge(entity), what enforces creation of a new EntityManager (So a new org.hibernate.internal.SessionImpl is created). On this object hibernate calls SessionImpl.merge(...). But in the method org.hibernate.internal.AbstractSharedSessionContract.createQuery(String) a other SessionImpl object is used, which is already closed in the request before. That enforces an java.lang.IllegalStateException: Session/EntityManager is closed.
In one sentence: Although a new entityManager was created and a merge was called on that new entityManger, Hibernate uses an old Session/EntityManager of the request before.
I debugged the problem and found following:
Debug1: Shows the Stacktrace of the SessionImpl.merge(...) with the session's object id
Debug2: Shows the last method with the correct SessionImpl object (see it's id). This object is not used in next methods.
Debug3: The step after Debug2 does not know the given SessionImpl object. It has it's own SessionImpl object in collection.initializor.versionsReader. This session was created and closed in the request before (on loading the page).
Debug4: Now Hibernate wants to create the query wit the closed SessionImpl
Debug5: This enforces the exception, as the session is closed.
My questions:
Is this a bug of Hibernate?
Why is the given SessionImpl in method org.hibernate.type.CollectionType.getElementIterater(...) not used?
Anyone knows a solution or workaround for this problem?
Tank you very much for any idea. I spent days on this bug.
Why is the Session arg in o.h.type.CollectionType.getElementIterator not used?
The short answer is it isn't required, its simply a backward compatibility concern from 8 years ago.
The long answer is the type-system used to actually deviate some behavior based on whether or not the user had specified the session to operate in EntityMode.MAP or EntityMode.POJO and therefore the types needed to know what mode the session was in; hence why it was passed.
But even back in 2011 when this was changed, the session argument only ever influenced behavior if and only if the session was operating in EntityMode.MAP. In other words, all other modes always routed directly to the underlying collections Collection#iterator() method.
All this aside however, this doesn't have any impact on what you experience in your Debug3 screen-shot.
Is this a bug in Hibernate?
No, based on what I have read, I believe you're mixing concerns.
In Hibernate (no Envers), you can basically do this
// Request 1
request1EntityManager = getEntityManager();
sessionScopeEntity = request1EntityManager.find( MyEntity.class, myEntityId );
// Request 2
request2EntityManager = getEntityManager();
sessionScopeEntity = request2EntityManager.merge( sessionScopeEntity );
for ( SomeCollectionItem Item : sessionScopeEntity.getSomeCollection() ) {
// do things here
}
The above works because you reassociate the entity with the new session which in-turn injects the session into all the uninitialized proxies the entity maintains. But you can also rewrite the above as
// Request 1
request1EntityManager = getEntityManager();
sessionScopeEntity = request1EntityManager.find( MyEntity.class, myEntityId );
sessionScopeEntity.getSomeCollection().size() // initialize collection w/request1Session
// Request 2
request2EntityManager = getEntityManager();
for ( SomeCollectionItem Item : sessionScopeEntity.getSomeCollection() ) {
// do things here
}
The difference is the collection gets initialized with the first session and therefore when you attempt to access it with the second session, the entity doesn't necessarily need a merge because the collection is no longer a proxy but actually populated like a normal fetched collection would be.
The major difference between an entity instance returned by Hibernate and an audited entity instance returned by Envers is that the audited entity instance is NOT a managed persistent entity.
Depending on your scenario, you may decide to only audit a subset of fields on an entity mapping. This is why you cannot nor should not use things like merge with that instance as it could easily lead to unintended side effects with your real data.
If you intend to pass the audited entity instance across sessions, i would highly suggest that you instead consider initializing the collections you need up-front with the first session where you fetched the instance because presently there is no way to re-associate an audited entity instance with a new session.

resetStateMachine does not clear its id

I am using a pooled list of StateMachine instances (at present limited to one) and am switching the context that statemachine is working with - however the StateMachine ID is never updated and I end up overwriting my statemachine in the db when i try to persist. More info on how below as well as the question.
My question is why upon calling resetStateMachine (in AbstractStateMachine.java) with a null context (ie trying to create a new context) does this not clear out the current id of the machine (I understand why UUID stays - that is unique to the machine) but id relates to the context also, no? If the context is not null it tries to pull the id from the stateMachineContext
Extracts of relevant sources:
If context is null:
log.info("Got null context, resetting to initial state and clearing extended state");
this.currentState = this.initialState;
this.extendedState.getVariables().clear();
If context is not null:
this.setId(stateMachineContext.getId());
When I later call persist.restore to pull back a state machine context this means I have an old id present and end up overwriting rather than using a new id to persist with.
This is using currently released version 1.2.5.RELEASE
Yes, don't see any reason why we would not clear id as well if null context is passed. Would you mind creating a github issue to track that change request?

spring entity concurrency control while persisting into database

I am trying to control concurrent access to same object in spring+jpa configuration.
For Example, I have an entity named A. Now multiple processes updating the same object of A.
I am using versioning field but controlling it but here is the issue:
For example 2 processes reads the same entity (A) having version=1.
Now one process update the entity and version gets incremented.
when 2nd process tries to persist the object, Optimistic lock exception would be thrown.
I am using spring services and repository to access the objects.
Could you please help me here?
What's the problem then? That's how it's supposed to work.
You can catch the JpaOptimisticLockingFailureException and then decide what to do from there.
This, for example, would give a validation error message on a Spring MVC form:
...
if(!bindingResult.hasErrors()) {
try {
fooRepository.save(foo);
} catch (JpaOptimisticLockingFailureException exp){
bindingResult.reject("", "This record was modified by another user. Try refreshing the page.");
}
}
...

How to implement session that tied with user login in struts2?

I have this application flow with struts2:
Page_A.jsp contain form that can submit a data to ActionA class with method executeA
ActionA->executeA method stores data in a sesion with key "myKey"
ActionA return result to Page_B.jsp
Page_B.jsp contains form that can submit a data to ActionA class with method executeB
In ActionA->executeB method, it will get the submitted data from the "myKey" session
I found out there are two ways to set and get the data from session:
Using ActionContext
// put the data into session
Map session = ActionContext.getContext().getSession();
session.put("myKey", data);
// get the data from session
Map session = ActionContext.getContext().getSession();
data = (String[]) session.get("myKey");
Using ServletActionContext
// put the data into session
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession(false);
session.setAttribute("myKey", data);
// get the data from session
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession(false);
data = (String[]) session.getAttribute("myKey");
Between the two ways, which one is the better way? Or is there an alternative better way? (I prefer the simple way if there is)
Second thing, I want to make sure the session is tied with user login session. That means "myKey" session data for one user will be different from "myKey" session data from another user (the "myKey" session data will never get overwritten by "myKey" session data from another user).
For example:
User1 login
User1 goes to Page_A.jsp and submit the data and now he's in Page_B.jsp (now the "myKey" session contains data submitted by User1)
User2 login
User2 goes to Page_A.jsp and submit the data too
I'm worried if User1 do submit from Page_B.jsp, will the data from "myKey" still refer to original data that he submitted or he will get the data from User2 (because the "myKey" session data was replaced) ?
Use ActionContext.getContext().getSession(); if you are working in an interceptor because it does not have the DI the actions have, for an action on the other hand add the SessionAware interface and the session will be injected.
The injection method lowers coupling and makes it easier to test your actions.
Both the above assume you don't need the full HttpServletRequest interface (which has far more functionality than just as map of parameters): http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html
Should you need this interface then ServletActionContext.getRequest(); is of course correct. Once again in the action you can lower coupling by using ServletRequestAware which will inject HttpServletRequest for you.
If you only need a property map then just use the methods which provide you with a map. Again this is because it's a lot easier to test and the intention is clear.
Sessions are unique, and they are maintained by the application server. For simplicity, when a user is using your application you can rest assured that there is a session.

Resources