Brought sandbox code to formatting guidelines

This commit is contained in:
Ben Hale
2007-08-13 16:18:35 +00:00
parent 67a05c196d
commit 59c2d3779b
16 changed files with 564 additions and 552 deletions

View File

@@ -2,11 +2,11 @@ package org.springframework.util;
/**
* Read-only resource holder.
*
*
* @author Maxim Petrashev
*/
public abstract class AbstractReadOnlyResourceHolder<E> extends AbstractResourceHolder<E> {
public final void set(E aObject) {
throw new UnsupportedOperationException();
}
public final void set(E aObject) {
throw new UnsupportedOperationException();
}
}

View File

@@ -6,19 +6,19 @@ import java.lang.reflect.Method;
/**
* Base abstract implementation of resource holder that implement method replacment logic.
*
*
* @author Maxim Petrashev
*/
public abstract class AbstractResourceHolder<E> implements ResourceHolder<E>
, MethodReplacer {//todo replace on injector in config
public abstract class AbstractResourceHolder<E> implements ResourceHolder<E>, MethodReplacer {// todo replace on
// injector in config
@SuppressWarnings("unchecked")
public Object reimplement(Object aObj, Method aMethod, Object[] aArgs) throws Throwable {
Object retVal = null;
if( aArgs.length == 0 ){
retVal = get();
} else {
set( (E) aArgs[0] );
}
return retVal;
}
public Object reimplement(Object aObj, Method aMethod, Object[] aArgs) throws Throwable {
Object retVal = null;
if (aArgs.length == 0) {
retVal = get();
} else {
set((E) aArgs[0]);
}
return retVal;
}
}

View File

@@ -2,10 +2,11 @@ package org.springframework.util;
/**
* Base interface for object holder concept.
*
*
* @author Maxim Petrashev
*/
public interface ResourceHolder<E> {
E get();
void set(E aObject);
E get();
void set(E aObject);
}

View File

@@ -5,92 +5,93 @@ import org.springframework.webflow.core.collection.MutableAttributeMap;
/**
* Listener interface for callback notification about phases in during conversation
*
*
* @author Maxim Petrashev
*/
public interface ConversationLifecycleListener {
/**
* Invoked when a flow is launched. The launching flow is not active.
*
* @param aNewFlow The launching flow
* @param aContext The request context
*/
/**
* Invoked when a flow is launched. The launching flow is not active.
*
* @param aNewFlow The launching flow
* @param aContext The request context
*/
void startingFlow(FlowDefinition aNewFlow, RequestContext aContext);
void startingFlow(FlowDefinition aNewFlow, RequestContext aContext);
void flowStarted(RequestContext aContext, MutableAttributeMap aInput);
/**
* Invoked when the root flow session has ended.
*
* @param aEndedSession The ended session
* @param aContext The request context
*/
void flowEnded(FlowSession aEndedSession, RequestContext aContext);
void flowStarted(RequestContext aContext, MutableAttributeMap aInput);
void endingFlow(RequestContext aContext, MutableAttributeMap aOutput);
/**
* Invoked in parent flow before spawning in subflow but after input mapping has been happened.
* The child flow session is not available to implementations of this method because the flow session for
* the child flow has not yet started. <p/> If you need to add items to the
* subflow scope, put them in aInput.
*
* @param aParentSession The active parent flow session
* @param aChild The child flow
* @param aContext The request context
* @param aInput The input map
*/
void startingSubflow(FlowSession aParentSession, FlowDefinition aChild, RequestContext aContext
, MutableAttributeMap aInput);
/**
* Invoked when a subflow is launched. The child flow session is not
* available to implementations of this method because the flow session for
* the child flow has not yet started. <p/> If you need to add items to the
* subflow scope, put them in aInput.
*
* @param aContext The request context
* @param aInput The input map
*/
void subflowStarted(RequestContext aContext , MutableAttributeMap aInput);
/**
* Invoked in subflow flow before spawning back to parent flot but after output mapping has been happened.
* The parent flow session is not available to implementations of this method because the flow session for
* the parent flow has not yet continued. <p/> If you need to add items to the
* parent flow scope, put them in aOutput.
*
* @param aContext The request context
* @param aOutput The input map
*/
void endingSubflow(RequestContext aContext , MutableAttributeMap aOutput);
/**
* Invoked when a parent flow is launched back. The child flow session is not
* available to implementations of this method because the flow session for
* the child flow has not yet started. <p/> If you need to add items to the
* subflow scope, put them in aInput.
*
* @param aParentSession The active parent flow session
* @param aChild The child flow
* @param aContext The request context
* @param aOutput The input map
*/
void subflowEnded(FlowSession aParentSession, FlowDefinition aChild, RequestContext aContext
, MutableAttributeMap aOutput);
/**
* The currently executing flow session is active. This occurs after the
* first event for the executing request has been signaled or resume event has been happended. Invoked once per
* request and provides access to the active flow session prior to any
* actions being performed.
*
* @param aContext The request context
*/
void sessionActive(RequestContext aContext);
/**
* The currently executing flow session is active. This occurs after the
* first event for the executing request has been signaled or resume event has been happended. Invoked once per
* request and provides access to the active flow session prior to any
* actions being performed.
*
* @param aContext The request context
*/
void sessionDeactive(RequestContext aContext);
/**
* Invoked when the root flow session has ended.
*
* @param aEndedSession The ended session
* @param aContext The request context
*/
void flowEnded(FlowSession aEndedSession, RequestContext aContext);
void endingFlow(RequestContext aContext, MutableAttributeMap aOutput);
/**
* Invoked in parent flow before spawning in subflow but after input mapping has been happened. The child flow
* session is not available to implementations of this method because the flow session for the child flow has not
* yet started. <p/> If you need to add items to the subflow scope, put them in aInput.
*
* @param aParentSession The active parent flow session
* @param aChild The child flow
* @param aContext The request context
* @param aInput The input map
*/
void startingSubflow(FlowSession aParentSession, FlowDefinition aChild, RequestContext aContext,
MutableAttributeMap aInput);
/**
* Invoked when a subflow is launched. The child flow session is not available to implementations of this method
* because the flow session for the child flow has not yet started. <p/> If you need to add items to the subflow
* scope, put them in aInput.
*
* @param aContext The request context
* @param aInput The input map
*/
void subflowStarted(RequestContext aContext, MutableAttributeMap aInput);
/**
* Invoked in subflow flow before spawning back to parent flot but after output mapping has been happened. The
* parent flow session is not available to implementations of this method because the flow session for the parent
* flow has not yet continued. <p/> If you need to add items to the parent flow scope, put them in aOutput.
*
* @param aContext The request context
* @param aOutput The input map
*/
void endingSubflow(RequestContext aContext, MutableAttributeMap aOutput);
/**
* Invoked when a parent flow is launched back. The child flow session is not available to implementations of this
* method because the flow session for the child flow has not yet started. <p/> If you need to add items to the
* subflow scope, put them in aInput.
*
* @param aParentSession The active parent flow session
* @param aChild The child flow
* @param aContext The request context
* @param aOutput The input map
*/
void subflowEnded(FlowSession aParentSession, FlowDefinition aChild, RequestContext aContext,
MutableAttributeMap aOutput);
/**
* The currently executing flow session is active. This occurs after the first event for the executing request has
* been signaled or resume event has been happended. Invoked once per request and provides access to the active flow
* session prior to any actions being performed.
*
* @param aContext The request context
*/
void sessionActive(RequestContext aContext);
/**
* The currently executing flow session is active. This occurs after the first event for the executing request has
* been signaled or resume event has been happended. Invoked once per request and provides access to the active flow
* session prior to any actions being performed.
*
* @param aContext The request context
*/
void sessionDeactive(RequestContext aContext);
}

View File

@@ -4,41 +4,44 @@ import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.core.collection.MutableAttributeMap;
/**
*
*
* @author Maxim Petrashev
*/
public abstract class ConversationLifecycleListenerAdapter implements ConversationLifecycleListener {
public void startingFlow(FlowDefinition aNewFlow, RequestContext aContext) {
}
public void startingFlow(FlowDefinition aNewFlow, RequestContext aContext) {
}
public void flowStarted(RequestContext aContext, MutableAttributeMap aInput) {
}
public void flowStarted(RequestContext aContext, MutableAttributeMap aInput) {
}
public void flowEnded(FlowSession aEndedSession, RequestContext aContext) {
}
public void flowEnded(FlowSession aEndedSession, RequestContext aContext) {
}
public void endingFlow(RequestContext aContext, MutableAttributeMap aOutput) {
}
public void endingFlow(RequestContext aContext, MutableAttributeMap aOutput) {
}
public void startingSubflow(FlowSession aParentSession, FlowDefinition aChild, RequestContext aContext, MutableAttributeMap aInput) {
}
public void startingSubflow(FlowSession aParentSession, FlowDefinition aChild, RequestContext aContext,
MutableAttributeMap aInput) {
}
public void subflowStarted(RequestContext aContext, MutableAttributeMap aInput) {
}
public void subflowStarted(RequestContext aContext, MutableAttributeMap aInput) {
}
public void subflowStarted(FlowSession aParentSession, FlowDefinition aChild, RequestContext aContext, MutableAttributeMap aInput) {
}
public void subflowStarted(FlowSession aParentSession, FlowDefinition aChild, RequestContext aContext,
MutableAttributeMap aInput) {
}
public void endingSubflow(RequestContext aContext, MutableAttributeMap aOutput) {
}
public void endingSubflow(RequestContext aContext, MutableAttributeMap aOutput) {
}
public void subflowEnded(FlowSession aParentSession, FlowDefinition aChild, RequestContext aContext, MutableAttributeMap aOutput) {
}
public void subflowEnded(FlowSession aParentSession, FlowDefinition aChild, RequestContext aContext,
MutableAttributeMap aOutput) {
}
public void sessionActive(RequestContext aContext) {
}
public void sessionActive(RequestContext aContext) {
}
public void sessionDeactive(RequestContext aContext) {
}
public void sessionDeactive(RequestContext aContext) {
}
}

View File

@@ -9,173 +9,167 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A listener/interceptor whose purpose is to adapt a HandlerInterceptor and
* FlowExecutionListener to provide expanded coverage at the beginning and
* ending of a request coming into a flow controller. The idea is to signal when
* a flow starts/activates, then signal when it has deactivated or ended. In
* addition, it should be signaled when a subflow starts/activates and
* ends/deactivates.
* A listener/interceptor whose purpose is to adapt a HandlerInterceptor and FlowExecutionListener to provide expanded
* coverage at the beginning and ending of a request coming into a flow controller. The idea is to signal when a flow
* starts/activates, then signal when it has deactivated or ended. In addition, it should be signaled when a subflow
* starts/activates and ends/deactivates.
* </p>
* Adapted from Alex Wolfe's post at <a
* href="http://forum.springframework.org/showthread.php?t=17633">
* Adapted from Alex Wolfe's post at <a href="http://forum.springframework.org/showthread.php?t=17633">
* http://forum.springframework.org/showthread.php?t=17633</a>
*
*
*
*
* @author Andrew Ebaugh
* @author Maxim Petrashev
*/
public class ExtendedFlowExecutionListenerInterceptor extends FlowExecutionListenerAdapter {
protected final Log _logger = LogFactory.getLog(getClass());
protected final Log _logger = LogFactory.getLog(getClass());
private static String FIRST_EVENT_SIGNALED = ExtendedFlowExecutionListenerInterceptor.class.getName() + ".FIRST_EVENT_SIGNALED";
private static String CURRENT_SESSION_ENDED = ExtendedFlowExecutionListenerInterceptor.class.getName() + ".CURRENT_SESSION_ENDED";
private static String FIRST_EVENT_SIGNALED = ExtendedFlowExecutionListenerInterceptor.class.getName()
+ ".FIRST_EVENT_SIGNALED";
private static String CURRENT_SESSION_ENDED = ExtendedFlowExecutionListenerInterceptor.class.getName()
+ ".CURRENT_SESSION_ENDED";
public ExtendedFlowExecutionListenerInterceptor(ConversationLifecycleListener aConversationLifecycleListener) {
_conversationLifecycleListener = aConversationLifecycleListener;
}
public ExtendedFlowExecutionListenerInterceptor(ConversationLifecycleListener aConversationLifecycleListener) {
_conversationLifecycleListener = aConversationLifecycleListener;
}
private ConversationLifecycleListener _conversationLifecycleListener;
private ConversationLifecycleListener _conversationLifecycleListener;
/**
* Called when any client request is submitted to manipulate this flow execution. Sets a flag in the request scope
* that is activated when the first state is entered during this request. This flag is required in order to trigger
* execution of the {@link ConversationLifecycleListener#sessionActive(RequestContext)} method.
*
* @param aContext The request aContext
*/
public final void requestSubmitted(RequestContext aContext) {
aContext.getRequestScope().put(FIRST_EVENT_SIGNALED, Boolean.FALSE);
aContext.getRequestScope().put(CURRENT_SESSION_ENDED, Boolean.FALSE);
}
/**
* Called when any client request is submitted to manipulate this flow
* execution. Sets a flag in the request scope that is activated when the
* first state is entered during this request. This flag is required in
* order to trigger execution of the {@link ConversationLifecycleListener#sessionActive(RequestContext)}
* method.
*
* @param aContext The request aContext
*/
public final void requestSubmitted(RequestContext aContext) {
aContext.getRequestScope().put(FIRST_EVENT_SIGNALED, Boolean.FALSE);
aContext.getRequestScope().put(CURRENT_SESSION_ENDED, Boolean.FALSE);
}
public final void eventSignaled(RequestContext aContext, Event aEvent) {
signalAction(aContext);
}
public final void eventSignaled(RequestContext aContext, Event aEvent) {
signalAction(aContext);
}
public final void stateEntered(RequestContext aContext, StateDefinition aPreviousState, StateDefinition aState) {
signalAction(aContext);
}
public final void stateEntered(RequestContext aContext, StateDefinition aPreviousState, StateDefinition aState) {
signalAction(aContext);
}
/**
* Called when an event is signaled, or a state is entered, but before any potential transition or actions occurs.
* If the action signaled is the first for the request, then the
* {@link ConversationLifecycleListener#sessionActive(RequestContext)} method is invoked. It is necessary that this
* be called prior to any state transitions to provide listeners coverage of any state exit/transition/entry
* actions.
*
* @param aContext The request aContext
*/
private void signalAction(RequestContext aContext) {
if (!firstEventSignaled(aContext)) {
aContext.getRequestScope().put(FIRST_EVENT_SIGNALED, Boolean.TRUE);
_conversationLifecycleListener.sessionActive(aContext);
}
}
/**
* Called when an event is signaled, or a state is entered, but before any
* potential transition or actions occurs. If the action signaled is the
* first for the request, then the {@link ConversationLifecycleListener#sessionActive(RequestContext)}
* method is invoked. It is necessary that this be called prior to any state
* transitions to provide listeners coverage of any state
* exit/transition/entry actions.
*
* @param aContext The request aContext
*/
private void signalAction(RequestContext aContext) {
if (!firstEventSignaled(aContext)) {
aContext.getRequestScope().put(FIRST_EVENT_SIGNALED, Boolean.TRUE);
_conversationLifecycleListener.sessionActive(aContext);
}
}
/**
* A aFlow session is starting. This method invokes
* {@link ConversationLifecycleListener#startingFlow(FlowDefinition, RequestContext)} if the launching aFlow session
* is the root aFlow. Otherwise, the
* {@link ConversationLifecycleListener#startingSubflow(FlowSession, FlowDefinition, RequestContext,MutableAttributeMap)}
* method is invoked.
*
* @param aContext The request aContext
* @param aFlowDefinition
* @param aInput
* @throws EnterStateVetoException The start state transition was not allowed
*/
public final void sessionStarting(RequestContext aContext, FlowDefinition aFlowDefinition,
MutableAttributeMap aInput) {
aContext.getRequestScope().put(FIRST_EVENT_SIGNALED, Boolean.TRUE);
aContext.getRequestScope().put(CURRENT_SESSION_ENDED, Boolean.FALSE);
FlowExecutionContext executionContext = aContext.getFlowExecutionContext();
FlowSession activeSession = executionContext.isActive() ? executionContext.getActiveSession() : null;
// when starting in default subflow start state?
if (activeSession != null && SubflowState.class.isInstance(activeSession.getState())) {
aFlowDefinition = ((SubflowState) activeSession.getState()).getSubflow();
}
/**
* A aFlow session is starting. This method invokes
* {@link ConversationLifecycleListener#startingFlow(FlowDefinition, RequestContext)} if the launching aFlow
* session is the root aFlow. Otherwise, the
* {@link ConversationLifecycleListener#startingSubflow(FlowSession, FlowDefinition, RequestContext,MutableAttributeMap)} method is
* invoked.
*
* @param aContext The request aContext
* @param aFlowDefinition
* @param aInput
* @throws EnterStateVetoException
* The start state transition was not allowed
*/
public final void sessionStarting(RequestContext aContext, FlowDefinition aFlowDefinition, MutableAttributeMap aInput) {
aContext.getRequestScope().put(FIRST_EVENT_SIGNALED, Boolean.TRUE);
aContext.getRequestScope().put(CURRENT_SESSION_ENDED, Boolean.FALSE);
FlowExecutionContext executionContext = aContext.getFlowExecutionContext();
FlowSession activeSession = executionContext.isActive() ? executionContext .getActiveSession() : null;
// when starting in default subflow start state?
if (activeSession != null
&& SubflowState.class.isInstance(activeSession.getState())) {
aFlowDefinition = ((SubflowState) activeSession.getState()).getSubflow();
}
if (activeSession == null) {
_conversationLifecycleListener.startingFlow(aFlowDefinition, aContext);
} else {
_conversationLifecycleListener.startingSubflow(activeSession, aFlowDefinition, aContext, null);
}
}
if (activeSession == null) {
_conversationLifecycleListener.startingFlow(aFlowDefinition, aContext);
} else {
_conversationLifecycleListener.startingSubflow(activeSession, aFlowDefinition, aContext, null);
}
}
public void sessionStarted(RequestContext aContext, FlowSession aSession) {
if (aSession.isRoot()) {
_conversationLifecycleListener.flowStarted(aContext, null);
} else {
_conversationLifecycleListener.subflowStarted(aContext, null);
}
}
public void sessionStarted(RequestContext aContext, FlowSession aSession) {
if( aSession.isRoot() ) {
_conversationLifecycleListener.flowStarted(aContext, null );
} else {
_conversationLifecycleListener.subflowStarted(aContext,null);
}
}
public void sessionEnding(RequestContext aContext, FlowSession aSession, MutableAttributeMap aOutput) {
if (aSession.isRoot()) {
_conversationLifecycleListener.endingFlow(aContext, null);
} else {
_conversationLifecycleListener.endingSubflow(aContext, null);
}
}
public void sessionEnding(RequestContext aContext, FlowSession aSession, MutableAttributeMap aOutput) {
if( aSession.isRoot() ) {
_conversationLifecycleListener.endingFlow(aContext, null );
} else {
_conversationLifecycleListener.endingSubflow(aContext,null);
}
}
public void requestProcessed(RequestContext aContext) {
FlowExecutionContext executionContext = aContext.getFlowExecutionContext();
if (executionContext.isActive()) {
_conversationLifecycleListener.sessionDeactive(aContext);
}
}
public void requestProcessed(RequestContext aContext) {
FlowExecutionContext executionContext = aContext.getFlowExecutionContext();
if( executionContext.isActive() ) {
_conversationLifecycleListener.sessionDeactive(aContext );
}
}
/**
* Called when a flow execution session ends. If the ended session was the root session of the flow execution, the
* {@link ConversationLifecycleListener#flowEnded(FlowSession, RequestContext)} method is invoked. <p/> If the ended
* session was not the root session, then the
* {@link ConversationLifecycleListener#subflowEnded(FlowSession, FlowDefinition, RequestContext, MutableAttributeMap)} }
* method is invoked. Prior to this, and in either case, the
* {@link ConversationLifecycleListener#sessionDeactive(RequestContext)} method is invoked.
*
* @param aContext The source of the event
* @param aEndedSession The ended FlowSession
*/
public final void sessionEnded(RequestContext aContext, FlowSession aEndedSession, AttributeMap aSessionOutput) {
FlowExecutionContext exeCtx = aContext.getFlowExecutionContext();
FlowSession newSession = exeCtx.isActive() ? exeCtx.getActiveSession() : null;
if (aEndedSession != null) {
try {
if (aEndedSession.isRoot()) {
_conversationLifecycleListener.flowEnded(aEndedSession, aContext);
} else {
_conversationLifecycleListener.subflowEnded(newSession, aEndedSession.getDefinition(), aContext,
null);
}
} catch (RuntimeException e) { // todo to think which base exception need wrap
String message = "Can't end session";
if (_logger.isWarnEnabled()) {
_logger.warn(message, e);
}
throw new FlowExecutionException(exeCtx.getDefinition().getId(), newSession != null ? newSession
.getState().getId() : aEndedSession.getState().getId(), message, e);
}
}
aContext.getRequestScope().put(CURRENT_SESSION_ENDED, Boolean.TRUE);
}
/**
* Called when a flow execution session ends. If the ended session was the
* root session of the flow execution, the
* {@link ConversationLifecycleListener#flowEnded(FlowSession, RequestContext)} method is
* invoked. <p/> If the ended session was not the root session, then the
* {@link ConversationLifecycleListener#subflowEnded(FlowSession, FlowDefinition, RequestContext, MutableAttributeMap)} }
* method is invoked. Prior to this, and in either case, the
* {@link ConversationLifecycleListener#sessionDeactive(RequestContext)} method is invoked.
*
* @param aContext The source of the event
* @param aEndedSession The ended FlowSession
*/
public final void sessionEnded(RequestContext aContext, FlowSession aEndedSession, AttributeMap aSessionOutput) {
FlowExecutionContext exeCtx = aContext.getFlowExecutionContext();
FlowSession newSession = exeCtx.isActive() ? exeCtx.getActiveSession() : null;
if (aEndedSession != null) {
try{
if (aEndedSession.isRoot()) {
_conversationLifecycleListener.flowEnded(aEndedSession, aContext);
} else {
_conversationLifecycleListener.subflowEnded(newSession, aEndedSession.getDefinition(), aContext, null);
}
} catch( RuntimeException e ){ //todo to think which base exception need wrap
String message = "Can't end session";
if( _logger.isWarnEnabled() ) {
_logger.warn(message,e);
}
throw new FlowExecutionException( exeCtx.getDefinition().getId()
, newSession != null ? newSession.getState().getId() : aEndedSession.getState().getId()
, message, e);
}
}
aContext.getRequestScope().put(CURRENT_SESSION_ENDED, Boolean.TRUE);
}
/**
* Determine whether the current request has handled an event.
*
* @param aContext The request context
* @return <code>true</code> if an event has already been signaled during the current request, otherwise
* <code>false</code>
*/
private boolean firstEventSignaled(RequestContext aContext) {
return aContext.getRequestScope().get(FIRST_EVENT_SIGNALED).equals(Boolean.TRUE);
}
/**
* Determine whether the current request has handled an event.
*
* @param aContext The request context
* @return <code>true</code> if an event has already been signaled during
* the current request, otherwise <code>false</code>
*/
private boolean firstEventSignaled(RequestContext aContext) {
return aContext.getRequestScope().get(FIRST_EVENT_SIGNALED).equals(Boolean.TRUE);
}
public void resumed(RequestContext context) {
signalAction(context);
}
public void resumed(RequestContext context) {
signalAction(context);
}
}

View File

@@ -11,61 +11,65 @@ import javax.persistence.EntityManagerFactory;
/**
* Default abstract JPA implementation for {@link EntityManagerLifecycleController}.
*
*
* @author Maxim Petrashev
*/
public abstract class DefaultEntityManagerLifecycleController implements EntityManagerLifecycleController {
private EntityManagerFactory _entityManagerFactory;
private EntityManagerFactory _entityManagerFactory;
public DefaultEntityManagerLifecycleController(EntityManagerFactory aEntityManagerFactory) {
_entityManagerFactory = aEntityManagerFactory;
}
public DefaultEntityManagerLifecycleController(EntityManagerFactory aEntityManagerFactory) {
_entityManagerFactory = aEntityManagerFactory;
}
public void close(EntityManager aEntityManager) {
Assert.isTrue(aEntityManager.isOpen(), "Entity manager was already closed");
aEntityManager.close();
}
public void close(EntityManager aEntityManager) {
Assert.isTrue(aEntityManager.isOpen(), "Entity manager was already closed");
aEntityManager.close();
}
public void deactivate(EntityManager aEntityManager) {
unbind(aEntityManager);
if (_log.isDebugEnabled()) {
_log.debug("Entity manager unbinded: " + aEntityManager.isOpen());
}
}
public void deactivate(EntityManager aEntityManager) {
unbind(aEntityManager);
if (_log.isDebugEnabled()) {
_log.debug("Entity manager unbinded: " + aEntityManager.isOpen());
}
}
public EntityManager create() {
return _entityManagerFactory.createEntityManager();
}
public EntityManager create() {
return _entityManagerFactory.createEntityManager();
}
public void flush(EntityManager aEntityManager) {
try {
aEntityManager.flush();
} catch (RuntimeException e) {//todo review this code
aEntityManager.getTransaction().rollback();
throw e;
}
}
public void flush(EntityManager aEntityManager) {
try {
aEntityManager.flush();
} catch (RuntimeException e) {// todo review this code
aEntityManager.getTransaction().rollback();
throw e;
}
}
public void activate(EntityManager aEntityManager) {
bind(aEntityManager);
if (_log.isDebugEnabled()) {
_log.debug("Session activate: " + aEntityManager.isOpen());
}
}
protected void bind(EntityManager aEntityManager) {
TransactionSynchronizationManager.bindResource(_entityManagerFactory, new EntityManagerHolder(aEntityManager));
}
public void activate(EntityManager aEntityManager) {
bind(aEntityManager);
if (_log.isDebugEnabled()) {
_log.debug("Session activate: " + aEntityManager.isOpen());
}
}
protected void unbind( EntityManager aEntityManager ) {
synchronized(_entityManagerFactory){//todo is this need?
Assert.isTrue( TransactionSynchronizationManager.hasResource(_entityManagerFactory) ); //todo remove this code. Resource must be already present.
TransactionSynchronizationManager.unbindResource(_entityManagerFactory);
}
}
protected void bind(EntityManager aEntityManager) {
TransactionSynchronizationManager.bindResource(_entityManagerFactory, new EntityManagerHolder(aEntityManager));
}
protected EntityManagerFactory getEntityManagerFactory() {
return _entityManagerFactory;
}
protected void unbind(EntityManager aEntityManager) {
synchronized (_entityManagerFactory) {// todo is this need?
Assert.isTrue(TransactionSynchronizationManager.hasResource(_entityManagerFactory)); // todo remove this
// code. Resource
// must be already
// present.
TransactionSynchronizationManager.unbindResource(_entityManagerFactory);
}
}
protected final Log _log = LogFactory.getLog(getClass());
protected EntityManagerFactory getEntityManagerFactory() {
return _entityManagerFactory;
}
protected final Log _log = LogFactory.getLog(getClass());
}

View File

@@ -9,35 +9,37 @@ import javax.persistence.EntityManager;
* <code>org.hibernate.annotations.FlushModeType.MANUAL</code></li>
* <li>Binding/Unbinding persistence context resources for current thread</li>
* </ul>
*
*
* @author Maxim Petrashev
*/
public interface EntityManagerLifecycleController {
/**
* Create new entity manager and return wrapper for it with aId id.
*/
EntityManager create();
/**
* Create new entity manager and return wrapper for it with aId id.
*/
EntityManager create();
/**
* Reconnect entity manager and bind to current thread.
* @param aEntityManager
*/
void activate(EntityManager aEntityManager);
/**
* Disconnect current session and unbind from current thread.
* @param aEntityManager
*/
void deactivate(EntityManager aEntityManager);
/**
* Reconnect entity manager and bind to current thread.
* @param aEntityManager
*/
void activate(EntityManager aEntityManager);
/**
* Commit application transaction.
* @param aEntityManager
*/
void flush(EntityManager aEntityManager);
/**
* Close opened entity manager.
* @param aEntityManager
*/
void close(EntityManager aEntityManager);
/**
* Disconnect current session and unbind from current thread.
* @param aEntityManager
*/
void deactivate(EntityManager aEntityManager);
/**
* Commit application transaction.
* @param aEntityManager
*/
void flush(EntityManager aEntityManager);
/**
* Close opened entity manager.
* @param aEntityManager
*/
void close(EntityManager aEntityManager);
}

View File

@@ -12,130 +12,125 @@ import org.springframework.webflow.execution.ConversationLifecycleListenerAdapte
import org.springframework.webflow.execution.FlowExecutionContext;
import org.springframework.webflow.execution.FlowSession;
import org.springframework.webflow.execution.RequestContext;
/**
* Intended for those wating a long session model within webflows. A entity
* manager is created when the flow begins, and is disconnected and reconnected
* as necessary throughout the lifecycle of the flow. In particular, it should
* be thought of as both a
* {@link org.springframework.webflow.execution.FlowExecutionListener} and
* {@link WebRequestInterceptor}
* that binds a
* entity manager to the current thread for the activate span of a FlowSession.
* This implementation shares the entity manager between a parent flow and any
* subflows.
* Intended for those wating a long session model within webflows. A entity manager is created when the flow begins, and
* is disconnected and reconnected as necessary throughout the lifecycle of the flow. In particular, it should be
* thought of as both a {@link org.springframework.webflow.execution.FlowExecutionListener} and
* {@link WebRequestInterceptor} that binds a entity manager to the current thread for the activate span of a
* FlowSession. This implementation shares the entity manager between a parent flow and any subflows.
* </p>
* To facilitate the long session idea, objects within the flow will be
* reassociated with the jpa persistence context when the flow is
* re-activated. Deserialized jpa flow scope
* objects lose their association to the persistence context, and thus result in
* problems when you attempt to perform persistence operations (run into
* non-unique object exceptions, null sessions in persistent collections, and a
* host of other weird behaviors). There is a basic facility to apply a
* flushMode to new entity managers that are created, but not as
* sophisticated as that provided by a HibernateAccessor. Config example:
*
* To facilitate the long session idea, objects within the flow will be reassociated with the jpa persistence context
* when the flow is re-activated. Deserialized jpa flow scope objects lose their association to the persistence context,
* and thus result in problems when you attempt to perform persistence operations (run into non-unique object
* exceptions, null sessions in persistent collections, and a host of other weird behaviors). There is a basic facility
* to apply a flushMode to new entity managers that are created, but not as sophisticated as that provided by a
* HibernateAccessor. Config example:
*
* <pre>
* &lt;bean id=&quot;openEntityManagerFlowListener&quot;
* class=&quot;org.springframework.webflow.jpa.OpenEntityManagerPerConversationFlowListener&quot;&gt;
* &lt;constructor ref=&quot;_lifecycleController&quot;/&gt;
* &lt;/bean&gt;
* </pre>
*
*
* <p>
* Adapted from Alex Wolfe's post at <a
* href="http://forum.springframework.org/showthread.php?t=17633">
* Adapted from Alex Wolfe's post at <a href="http://forum.springframework.org/showthread.php?t=17633">
* http://forum.springframework.org/showthread.php?t=17633</a>
*
*
* @author Maxim Petrashev
*/
public class OpenEntityManagerPerConversationFlowListener extends ConversationLifecycleListenerAdapter {
protected final Log _logger = LogFactory.getLog( getClass() );
protected final Log _logger = LogFactory.getLog(getClass());
private final EntityManagerLifecycleController _lifecycleController;
private final EntityManagerLifecycleController _lifecycleController;
/**
* Attribute name for annotated state which mark end-state and application commit end-state.
*/
public static final String APPLICATION_TRANSACTION_COMMIT_ATTR_NAME = "applicationTransactionCommit";
/**
* Attribute name under wich in conversation scope will be stored entity manager for conversation.
*/
private static final String ENTITY_MANAGER_ATTR_NAME = OpenEntityManagerPerConversationFlowListener.class.getName() + ".ENTITY_MANAGER";
/**
* Attribute name for annotated state which mark end-state and application commit end-state.
*/
public static final String APPLICATION_TRANSACTION_COMMIT_ATTR_NAME = "applicationTransactionCommit";
/**
* Attribute name under wich in conversation scope will be stored entity manager for conversation.
*/
private static final String ENTITY_MANAGER_ATTR_NAME = OpenEntityManagerPerConversationFlowListener.class.getName()
+ ".ENTITY_MANAGER";
protected OpenEntityManagerPerConversationFlowListener(EntityManagerLifecycleController aLifecycleController ) {
_lifecycleController = aLifecycleController;
}
protected OpenEntityManagerPerConversationFlowListener(EntityManagerLifecycleController aLifecycleController) {
_lifecycleController = aLifecycleController;
}
protected EntityManager getEntityManager(RequestContext aContext){
return (EntityManager) aContext.getConversationScope().get( ENTITY_MANAGER_ATTR_NAME );
}
protected EntityManager getEntityManager(RequestContext aContext) {
return (EntityManager) aContext.getConversationScope().get(ENTITY_MANAGER_ATTR_NAME);
}
/**
* Create entity manager for new conversation.
* @param aNewFlow
* @param aContext
*/
public void startingFlow(FlowDefinition aNewFlow, RequestContext aContext) {
_logger.debug("Creating entity manager for flow: " + aNewFlow.getId());
EntityManager entityManager = _lifecycleController.create();
_lifecycleController.activate( entityManager );
aContext.getConversationScope().put(ENTITY_MANAGER_ATTR_NAME, entityManager);
}
/**
* Create entity manager for new conversation.
* @param aNewFlow
* @param aContext
*/
public void startingFlow(FlowDefinition aNewFlow, RequestContext aContext) {
_logger.debug("Creating entity manager for flow: " + aNewFlow.getId());
EntityManager entityManager = _lifecycleController.create();
_lifecycleController.activate(entityManager);
aContext.getConversationScope().put(ENTITY_MANAGER_ATTR_NAME, entityManager);
}
/**
* Try commit application transaction on application transaction commit end state.
* Clean also all resources that were allocated for conversation entity manager.
* @param aEndedSession
* @param aContext
*/
public void flowEnded(FlowSession aEndedSession, RequestContext aContext) {
EntityManager entityManager = getEntityManager(aContext);
try{
if (isApplicationTransactionCommitState(aEndedSession.getState())) {
_lifecycleController.flush(entityManager);
}
}finally{
try{
_lifecycleController.deactivate(entityManager);
}finally{
_lifecycleController.close( entityManager );
}
}
}
/**
* Try commit application transaction on application transaction commit end state. Clean also all resources that
* were allocated for conversation entity manager.
* @param aEndedSession
* @param aContext
*/
public void flowEnded(FlowSession aEndedSession, RequestContext aContext) {
EntityManager entityManager = getEntityManager(aContext);
try {
if (isApplicationTransactionCommitState(aEndedSession.getState())) {
_lifecycleController.flush(entityManager);
}
} finally {
try {
_lifecycleController.deactivate(entityManager);
} finally {
_lifecycleController.close(entityManager);
}
}
}
/**
* {@inheritDoc}
*/
public void sessionActive(RequestContext aContext) {
EntityManager entityManager = getEntityManager(aContext);
_lifecycleController.activate( entityManager );
}
/**
* {@inheritDoc}
*/
public void sessionActive(RequestContext aContext) {
EntityManager entityManager = getEntityManager(aContext);
_lifecycleController.activate(entityManager);
}
/**
* Deactivate current entity manager on end of request handling process.
*/
public void sessionDeactive(RequestContext aContext) {
FlowExecutionContext flowExecutionContext = aContext.getFlowExecutionContext();
if( flowExecutionContext.isActive() ) {//todo need CommandManager or request specific lifecycleController
EntityManager entityManager = getEntityManager(aContext);
_lifecycleController.deactivate( entityManager );
} else {
//entity manager already was closed in flowEnded method
}
}
/**
* Deactivate current entity manager on end of request handling process.
*/
public void sessionDeactive(RequestContext aContext) {
FlowExecutionContext flowExecutionContext = aContext.getFlowExecutionContext();
if (flowExecutionContext.isActive()) {// todo need CommandManager or request specific lifecycleController
EntityManager entityManager = getEntityManager(aContext);
_lifecycleController.deactivate(entityManager);
} else {
// entity manager already was closed in flowEnded method
}
}
/**
* Return is aState application commit state or not. Returns true if aState is EndState and aState is annotated
* by {@link #APPLICATION_TRANSACTION_COMMIT_ATTR_NAME} attribute.
*/
protected boolean isApplicationTransactionCommitState(StateDefinition aState) {
boolean retVal = false;
if (aState instanceof EndState) {
retVal = aState.getAttributes().get(APPLICATION_TRANSACTION_COMMIT_ATTR_NAME, "false").equals("true");
}
return retVal;
}
/**
* Return is aState application commit state or not. Returns true if aState is EndState and aState is annotated by
* {@link #APPLICATION_TRANSACTION_COMMIT_ATTR_NAME} attribute.
*/
protected boolean isApplicationTransactionCommitState(StateDefinition aState) {
boolean retVal = false;
if (aState instanceof EndState) {
retVal = aState.getAttributes().get(APPLICATION_TRANSACTION_COMMIT_ATTR_NAME, "false").equals("true");
}
return retVal;
}
public static final String CURRENT_ENTITY_MANAGER_KEY_ATTR_NAME = OpenEntityManagerPerConversationFlowListener.class.getName() + ".CURRENT_ENTITY_MANAGER_KEY";
//todo review exceptionThrown
public static final String CURRENT_ENTITY_MANAGER_KEY_ATTR_NAME = OpenEntityManagerPerConversationFlowListener.class
.getName()
+ ".CURRENT_ENTITY_MANAGER_KEY";
// todo review exceptionThrown
}

View File

@@ -8,18 +8,18 @@ import javax.persistence.EntityManager;
/**
* Resource holder that is wrapper for TransactionSynchronizationManager.
*
*
* @author Maxim Petrashev
*/
public class TransactionSynchronizationManagerEnityManagerHolder extends AbstractReadOnlyResourceHolder<EntityManager> {
public EntityManager get() {
EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource( _key );
return emHolder.getEntityManager();
}
public EntityManager get() {
EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(_key);
return emHolder.getEntityManager();
}
public TransactionSynchronizationManagerEnityManagerHolder(Object aKey) {
_key = aKey;
}
public TransactionSynchronizationManagerEnityManagerHolder(Object aKey) {
_key = aKey;
}
private Object _key;
private Object _key;
}

View File

@@ -13,56 +13,61 @@ import javax.persistence.EntityTransaction;
/**
* Hibernate specific implementation of EntityManagerLifecycleController interface. Set for each new entity manager
* hibernate specific flush mode and starts new JPA transaction on activation, and commit it on deactivation
*
*
* @author Maxim Petrashev
*/
public class EntityManagerLifecycleController extends DefaultEntityManagerLifecycleController {
public EntityManagerLifecycleController(EntityManagerFactory aEntityManagerFactory) {
super(aEntityManagerFactory);
}
public EntityManager create() {
EntityManager retVal = super.create();
Session session = HibernateUtils.getSession(retVal);
session.setFlushMode(FlushMode.MANUAL); //todo review this code
return retVal;
}
protected void unbind( EntityManager aEntityManager ) {
try{
SessionFactory sessionFactory = HibernateUtils.getSessionFactory( getEntityManagerFactory() );
ManagedSessionContext.unbind(sessionFactory);
}finally{
super.unbind( aEntityManager );
}
}
public EntityManagerLifecycleController(EntityManagerFactory aEntityManagerFactory) {
super(aEntityManagerFactory);
}
protected void bind(EntityManager aEntityManager) {
super.bind(aEntityManager);
//todo remove this code in hibernate specific class
ManagedSessionContext.bind( HibernateUtils.getSession( aEntityManager ) );
}
public EntityManager create() {
EntityManager retVal = super.create();
Session session = HibernateUtils.getSession(retVal);
session.setFlushMode(FlushMode.MANUAL); // todo review this code
return retVal;
}
public void activate(EntityManager aEntityManager) {
beginTransaction(aEntityManager);
super.activate(aEntityManager);
}
protected void unbind(EntityManager aEntityManager) {
try {
SessionFactory sessionFactory = HibernateUtils.getSessionFactory(getEntityManagerFactory());
ManagedSessionContext.unbind(sessionFactory);
} finally {
super.unbind(aEntityManager);
}
}
public void deactivate(EntityManager aEntityManager) {
try{
disconnectSession(aEntityManager);
} finally {
super.deactivate(aEntityManager);
}
}
protected void bind(EntityManager aEntityManager) {
super.bind(aEntityManager);
// todo remove this code in hibernate specific class
ManagedSessionContext.bind(HibernateUtils.getSession(aEntityManager));
}
protected void beginTransaction(EntityManager aEntityManager) {//todo is it method need? May be transaction aspect has to cover it?
//begin database transaction for taking available connection
aEntityManager.getTransaction().begin();
}
protected void disconnectSession(EntityManager aEntityManager) {//todo is it method need? May be transaction aspect has to cover it?
EntityTransaction transaction = aEntityManager.getTransaction();
transaction.commit();
//todo is it need ? aSession.disconnect();
}
public void activate(EntityManager aEntityManager) {
beginTransaction(aEntityManager);
super.activate(aEntityManager);
}
public void deactivate(EntityManager aEntityManager) {
try {
disconnectSession(aEntityManager);
} finally {
super.deactivate(aEntityManager);
}
}
protected void beginTransaction(EntityManager aEntityManager) {// todo is it method need? May be transaction aspect
// has to cover it?
// begin database transaction for taking available connection
aEntityManager.getTransaction().begin();
}
protected void disconnectSession(EntityManager aEntityManager) {// todo is it method need? May be transaction aspect
// has to cover it?
EntityTransaction transaction = aEntityManager.getTransaction();
transaction.commit();
// todo is it need ? aSession.disconnect();
}
}

View File

@@ -15,30 +15,33 @@ import java.util.LinkedList;
/**
* Utils class for common hibernate JPA routines.
*
*
* @author Maxim Petrashev
*/
public abstract class HibernateUtils {
public static SessionFactory getSessionFactory(EntityManagerFactory aEntityManagerFactory) {
HibernateEntityManagerFactory hibernateEntityManagerFactory
= (HibernateEntityManagerFactory) aEntityManagerFactory;
return hibernateEntityManagerFactory.getSessionFactory();
}
public static Session getSession(EntityManager aEntityManager) {
return (Session) ((HibernateEntityManager)aEntityManager).getSession();
}
@Deprecated public static List<Class> getEntityClasses( EntityManager aEntityManager ) {
SessionFactory sessionFactory = getSession(aEntityManager).getSessionFactory();
@SuppressWarnings("unchecked")
Map<String, ClassMetadata> metadataMap = sessionFactory.getAllClassMetadata();
List<Class> retVal = new LinkedList<Class>();
for (ClassMetadata classMetadata : metadataMap.values()) {
Class type = classMetadata.getMappedClass(EntityMode.POJO);
retVal.add( type );
}
return retVal;
}
public static Object getIdentifier(SessionFactory aSessionFactory, Object aEntity) {
return aSessionFactory.getCurrentSession().getIdentifier( aEntity );
}
public static SessionFactory getSessionFactory(EntityManagerFactory aEntityManagerFactory) {
HibernateEntityManagerFactory hibernateEntityManagerFactory = (HibernateEntityManagerFactory) aEntityManagerFactory;
return hibernateEntityManagerFactory.getSessionFactory();
}
public static Session getSession(EntityManager aEntityManager) {
return (Session) ((HibernateEntityManager) aEntityManager).getSession();
}
@Deprecated
public static List<Class> getEntityClasses(EntityManager aEntityManager) {
SessionFactory sessionFactory = getSession(aEntityManager).getSessionFactory();
@SuppressWarnings("unchecked")
Map<String, ClassMetadata> metadataMap = sessionFactory.getAllClassMetadata();
List<Class> retVal = new LinkedList<Class>();
for (ClassMetadata classMetadata : metadataMap.values()) {
Class type = classMetadata.getMappedClass(EntityMode.POJO);
retVal.add(type);
}
return retVal;
}
public static Object getIdentifier(SessionFactory aSessionFactory, Object aEntity) {
return aSessionFactory.getCurrentSession().getIdentifier(aEntity);
}
}

View File

@@ -31,23 +31,23 @@ import javax.persistence.Transient;
@Entity
@Table(name = "T_SALES")
@Proxy(lazy=true)
@Proxy(lazy = true)
public class Sale implements Serializable {
@Id
@TableGenerator( name="ids" )
@GeneratedValue(strategy= GenerationType.TABLE)
public int getId() {
return id;
}
@Id
@TableGenerator(name = "ids")
@GeneratedValue(strategy = GenerationType.TABLE)
public int getId() {
return id;
}
public void setId(int aId) {
id = aId;
}
public void setId(int aId) {
id = aId;
}
private int id;
private int id;
private double price;
private double price;
private int itemCount;
@@ -113,22 +113,21 @@ public class Sale implements Serializable {
* Returns the base amount of the sale, without discount or delivery costs.
*/
@Transient
public double getAmount() {
public double getAmount() {
return price * itemCount;
}
/**
* Returns the discount rate to apply.
*/
@Transient
public double getDiscountRate() {
@Transient
public double getDiscountRate() {
double discount = 0.02;
if ("A".equals(category)) {
if (itemCount >= 100) {
discount = 0.1;
}
}
else if ("B".equals(category)) {
} else if ("B".equals(category)) {
if (itemCount >= 200) {
discount = 0.2;
}
@@ -139,21 +138,20 @@ public class Sale implements Serializable {
/**
* Returns the savings because of the discount.
*/
@Transient
public double getSavings() {
@Transient
public double getSavings() {
return getDiscountRate() * getAmount();
}
/**
* Returns the delivery cost.
*/
@Transient
public double getDeliveryCost() {
@Transient
public double getDeliveryCost() {
double delCost = 0.0;
if ("S".equals(shippingType)) {
delCost = 10.0;
}
else if ("E".equals(shippingType)) {
} else if ("E".equals(shippingType)) {
delCost = 20.0;
}
return delCost;
@@ -163,7 +161,7 @@ public class Sale implements Serializable {
* Returns the total cost of the sale, including discount and delivery cost.
*/
@Transient
public double getTotalCost() {
public double getTotalCost() {
return getAmount() + getDeliveryCost() - getSavings();
}

View File

@@ -18,7 +18,7 @@ package org.springframework.webflow.samples.sellitem;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
//todo remove dependency on Validator interface
// todo remove dependency on Validator interface
public class SaleValidator implements Validator {
public boolean supports(Class clazz) {
@@ -26,10 +26,10 @@ public class SaleValidator implements Validator {
}
public void validate(Object obj, Errors errors) {
Sale sale = (Sale)obj;
Sale sale = (Sale) obj;
validatePriceAndItemCount(sale, errors);
}
public void validatePriceAndItemCount(Sale sale, Errors errors) {
if (sale.getItemCount() <= 0) {
errors.rejectValue("itemCount", "tooLittle", "Item count must be greater than 0");

View File

@@ -29,7 +29,12 @@ public class SellItemFlowExecutionListener extends FlowExecutionListenerAdapter
public void stateEntering(RequestContext context, StateDefinition nextState) throws EnterStateVetoException {
String role = nextState.getAttributes().getString("role");
if (StringUtils.hasText(role)) {
HttpServletRequest request = ((ServletExternalContext)context.getExternalContext()).getRequest();//todo remove dependency on servlet api
HttpServletRequest request = ((ServletExternalContext) context.getExternalContext()).getRequest();// todo
// remove
// dependency
// on
// servlet
// api
if (!request.isUserInRole(role)) {
throw new EnterStateVetoException(context.getActiveFlow().getId(), context.getCurrentState().getId(),
nextState.getId(), "State requires role '" + role

View File

@@ -6,9 +6,10 @@ import org.springframework.webflow.samples.sellitem.Sale;
import javax.persistence.EntityManager;
public abstract class JpaSaleProcessor implements SaleProcessor {
public void process(Sale sale) {
EntityManager entityManager = getEntityManager();
entityManager.persist(sale);
}
protected abstract EntityManager getEntityManager();
public void process(Sale sale) {
EntityManager entityManager = getEntityManager();
entityManager.persist(sale);
}
protected abstract EntityManager getEntityManager();
}