diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorFactoryBean.java b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorFactoryBean.java index 18ed81c7..e0cd8195 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorFactoryBean.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/FlowExecutorFactoryBean.java @@ -175,7 +175,7 @@ class FlowExecutorFactoryBean implements FactoryBean, ApplicationContextAware, I DefaultFlowExecutionRepository repository = new DefaultFlowExecutionRepository(conversationManager, executionStateRestorer); if (maxFlowExecutionSnapshots != null) { - repository.setMaxContinuations(maxFlowExecutionSnapshots.intValue()); + repository.setMaxSnapshots(maxFlowExecutionSnapshots.intValue()); } return repository; } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/AbstractFlowExecutionContinuationRepository.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/AbstractSnapshottingFlowExecutionRepository.java similarity index 51% rename from spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/AbstractFlowExecutionContinuationRepository.java rename to spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/AbstractSnapshottingFlowExecutionRepository.java index 8c8ba635..032a753d 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/AbstractFlowExecutionContinuationRepository.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/AbstractSnapshottingFlowExecutionRepository.java @@ -15,60 +15,72 @@ */ package org.springframework.webflow.execution.repository.continuation; +import java.io.Serializable; + import org.springframework.util.Assert; import org.springframework.webflow.conversation.ConversationManager; import org.springframework.webflow.execution.FlowExecution; +import org.springframework.webflow.execution.FlowExecutionKey; import org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository; +import org.springframework.webflow.execution.repository.support.CompositeFlowExecutionKey; import org.springframework.webflow.execution.repository.support.FlowExecutionStateRestorer; /** - * Base class for repositories that create flow execution snapshots called "continuations". + * Base class for repositories that take flow execution snapshots using a {@link FlowExecutionSnapshotFactory}. * * @author Keith Donald */ -public abstract class AbstractFlowExecutionContinuationRepository extends AbstractFlowExecutionRepository { +public abstract class AbstractSnapshottingFlowExecutionRepository extends AbstractFlowExecutionRepository { /** - * The continuation factory that will be used to create new continuations to be added to active conversations. + * The factory to use to take flow execution snapshots. */ - private FlowExecutionContinuationFactory continuationFactory; + private FlowExecutionSnapshotFactory executionSnapshotFactory; /** - * Creates a new continuation repository. + * Creates a new snapshotting flow execution repository. * @param conversationManager the conversation manager * @param executionStateRestorer the execution state restorer - * @param continuationFactory the continuation factory + * @param executionSnapshotFactory the execution snapshot factory */ - public AbstractFlowExecutionContinuationRepository(ConversationManager conversationManager, - FlowExecutionStateRestorer executionStateRestorer, FlowExecutionContinuationFactory continuationFactory) { + public AbstractSnapshottingFlowExecutionRepository(ConversationManager conversationManager, + FlowExecutionStateRestorer executionStateRestorer, FlowExecutionSnapshotFactory executionSnapshotFactory) { super(conversationManager, executionStateRestorer); - Assert.notNull(continuationFactory, "The flow execution continuation factory is required"); - this.continuationFactory = continuationFactory; + Assert.notNull(executionSnapshotFactory, "The flow execution snapshot factory is required"); + this.executionSnapshotFactory = executionSnapshotFactory; } /** * Returns the configured flow execution snapshot factory. * @return the snapshot factory */ - public FlowExecutionContinuationFactory getContinuationFactory() { - return continuationFactory; + public FlowExecutionSnapshotFactory getExecutionSnapshotFactory() { + return executionSnapshotFactory; } /** - * Take a new continuation snapshot. - * @param flowExecution the execution to snapshot - * @return the continuation snapshot + * Returns the snapshotId portion of the flow execution key. + * @param key the execution key */ - protected FlowExecutionContinuation snapshot(FlowExecution flowExecution) { - return continuationFactory.createContinuation(flowExecution); + protected Serializable getSnapshotId(FlowExecutionKey key) { + return ((CompositeFlowExecutionKey) key).getSnapshotId(); + } + + /** + * Take a new flow execution snapshot. + * @param flowExecution the execution to snapshot + * @return the snapshot + */ + protected FlowExecutionSnapshot snapshot(FlowExecution flowExecution) { + return executionSnapshotFactory.createSnapshot(flowExecution); } /** * Deserialize a serialized flow execution. - * @param continuationBytes the flow execution snapshot byte array + * @param snapshotBytes the flow execution snapshot byte array * @return the deserialized flow execution */ - protected FlowExecution deserializeExecution(byte[] continuationBytes) { - return continuationFactory.restoreContinuation(continuationBytes).unmarshal(); + protected FlowExecution deserializeExecution(byte[] snapshotBytes) { + return executionSnapshotFactory.restoreSnapshot(snapshotBytes).unmarshal(); } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/ContinuationNotFoundException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/ContinuationNotFoundException.java deleted file mode 100644 index 2a5072e0..00000000 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/ContinuationNotFoundException.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2004-2008 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.webflow.execution.repository.continuation; - -import java.io.Serializable; - -import org.springframework.webflow.execution.repository.FlowExecutionRepositoryException; - -/** - * Thrown when no flow execution continuation exists within a continuation group with a particular id. This might occur - * if the continuation has expired or was explictly invalidated but a client's browser page cache still references it. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class ContinuationNotFoundException extends FlowExecutionRepositoryException { - - /** - * The unique continuation identifier that was not found. - */ - private Serializable continuationId; - - /** - * Creates a continuation not found exception. - * @param continuationId the continuation id that could not be found - */ - public ContinuationNotFoundException(Serializable continuationId) { - super("No flow execution continuation could be found in this group with id '" + continuationId - + "' -- perhaps the continuation has expired or has been invalidated? "); - this.continuationId = continuationId; - } - - /** - * Returns the continuation id that could not be found. - */ - public Serializable getContinuationId() { - return continuationId; - } -} \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionContinuation.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionSnapshot.java similarity index 71% rename from spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionContinuation.java rename to spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionSnapshot.java index f7b85991..ad6aa7aa 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionContinuation.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionSnapshot.java @@ -22,22 +22,22 @@ import org.springframework.webflow.execution.FlowExecution; /** * A snapshot of a flow execution that can be restored from and serialized to a byte array. * - * @see FlowExecutionContinuationFactory + * @see FlowExecutionSnapshotFactory * * @author Erwin Vervaet * @author Keith Donald */ -public abstract class FlowExecutionContinuation implements Serializable { +public abstract class FlowExecutionSnapshot implements Serializable { /** - * Restores the flow execution wrapped in this continuation. + * Returns underlying flow execution object. * @return the unmarshalled flow execution - * @throws ContinuationUnmarshalException when there is a problem unmarshalling this continuation + * @throws SnapshotUnmarshalException when there is a problem unmarshalling the execution */ - public abstract FlowExecution unmarshal() throws ContinuationUnmarshalException; + public abstract FlowExecution unmarshal() throws SnapshotUnmarshalException; /** - * Converts this continuation to a byte array for convenient serialization. + * Converts this snapshot to a byte array for convenient serialization. * @return this as a byte array */ public abstract byte[] toByteArray(); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionContinuationFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionSnapshotFactory.java similarity index 52% rename from spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionContinuationFactory.java rename to spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionSnapshotFactory.java index 91383bea..d8fe1630 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionContinuationFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/FlowExecutionSnapshotFactory.java @@ -18,27 +18,26 @@ package org.springframework.webflow.execution.repository.continuation; import org.springframework.webflow.execution.FlowExecution; /** - * A factory for creating different {@link FlowExecutionContinuation} implementations. + * A factory for creating different {@link FlowExecutionSnapshot} implementations. * * @author Keith Donald * @author Erwin Vervaet */ -public interface FlowExecutionContinuationFactory { +public interface FlowExecutionSnapshotFactory { /** - * Creates a new flow execution continuation for given flow execution. + * Takes a snapshot of the flow execution. * @param flowExecution the flow execution - * @return the continuation - * @throws ContinuationCreationException when the continuation cannot be created + * @return the new snapshot + * @throws SnapshotCreationException if the snapshot could not be created */ - public FlowExecutionContinuation createContinuation(FlowExecution flowExecution) - throws ContinuationCreationException; + public FlowExecutionSnapshot createSnapshot(FlowExecution flowExecution) throws SnapshotCreationException; /** - * Restore a flow execution continuation object from the provided byte array. - * @param bytes the flow execution byte array - * @return the continuation - * @throws ContinuationUnmarshalException when the continuation cannot be restored + * Restore a flow execution snapshot from a byte array. + * @param bytes the byte array + * @return the snapshot + * @throws SnapshotUnmarshalException if the snapshot could not be restored */ - public FlowExecutionContinuation restoreContinuation(byte[] bytes) throws ContinuationUnmarshalException; + public FlowExecutionSnapshot restoreSnapshot(byte[] bytes) throws SnapshotUnmarshalException; } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionContinuation.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionSnapshot.java similarity index 81% rename from spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionContinuation.java rename to spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionSnapshot.java index 34dbf2f2..79d9fedf 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionContinuation.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionSnapshot.java @@ -32,73 +32,66 @@ import org.springframework.util.FileCopyUtils; import org.springframework.webflow.execution.FlowExecution; /** - * A continuation implementation that is based on standard Java serialization, created by a - * {@link SerializedFlowExecutionContinuationFactory}. + * A snapshot implementation that is based on standard Java serialization, created by a + * {@link SerializedFlowExecutionSnapshotFactory}. * - * @see SerializedFlowExecutionContinuationFactory + * @see SerializedFlowExecutionSnapshotFactory * * @author Keith Donald * @author Erwin Vervaet */ -class SerializedFlowExecutionContinuation extends FlowExecutionContinuation implements Externalizable { +class SerializedFlowExecutionSnapshot extends FlowExecutionSnapshot implements Externalizable { - /** - * The serialized flow execution. - */ private byte[] flowExecutionData; - /** - * Whether or not the flow execution byte array is compressed. - */ private boolean compressed; /** * Default constructor necessary for {@link Externalizable} custom serialization semantics. Should not be called by * application code. */ - public SerializedFlowExecutionContinuation() { + public SerializedFlowExecutionSnapshot() { } /** - * Creates a new serialized flow execution continuation. This will marshall given flow execution into a serialized - * continuation form. + * Creates a new serialized flow execution snapshot. * @param flowExecution the flow execution - * @param compress whether or not the flow execution should be compressed + * @param compress whether or not to apply compression during snapshotting */ - public SerializedFlowExecutionContinuation(FlowExecution flowExecution, boolean compress) - throws ContinuationCreationException { + public SerializedFlowExecutionSnapshot(FlowExecution flowExecution, boolean compress) + throws SnapshotCreationException { try { flowExecutionData = serialize(flowExecution); if (compress) { flowExecutionData = compress(flowExecutionData); } } catch (NotSerializableException e) { - throw new ContinuationCreationException(flowExecution, "Could not serialize flow execution; " + throw new SnapshotCreationException(flowExecution, "Could not serialize flow execution; " + "make sure all objects stored in flow or flash scope are serializable", e); } catch (IOException e) { - throw new ContinuationCreationException(flowExecution, + throw new SnapshotCreationException(flowExecution, "IOException thrown serializing flow execution -- this should not happen!", e); } this.compressed = compress; } /** - * Returns whether or not the flow execution data in this continuation is compressed. + * Returns whether or not the flow execution data in this snapshot is compressed. */ public boolean isCompressed() { return compressed; } - public FlowExecution unmarshal() throws ContinuationUnmarshalException { + public FlowExecution unmarshal() throws SnapshotUnmarshalException { try { return deserialize(getFlowExecutionData()); } catch (IOException e) { - throw new ContinuationUnmarshalException( - "IOException thrown deserializing the flow execution stored in this continuation -- this should not happen!", + throw new SnapshotUnmarshalException( + "IOException thrown deserializing the flow execution stored in this snapshot -- this should not happen!", e); } catch (ClassNotFoundException e) { - throw new ContinuationUnmarshalException( - "ClassNotFoundException thrown deserializing the flow execution stored in this continuation -- " + throw new SnapshotUnmarshalException( + "ClassNotFoundException thrown deserializing the flow execution stored in this snapshot -- " + "This should not happen! Make sure there are no classloader issues. " + "For example, perhaps the Web Flow system is being loaded by a classloader " + "that is a parent of the classloader loading application classes?", e); @@ -122,10 +115,10 @@ class SerializedFlowExecutionContinuation extends FlowExecutionContinuation impl } public boolean equals(Object o) { - if (!(o instanceof SerializedFlowExecutionContinuation)) { + if (!(o instanceof SerializedFlowExecutionSnapshot)) { return false; } - SerializedFlowExecutionContinuation c = (SerializedFlowExecutionContinuation) o; + SerializedFlowExecutionSnapshot c = (SerializedFlowExecutionSnapshot) o; return Arrays.equals(flowExecutionData, c.flowExecutionData); } @@ -156,7 +149,7 @@ class SerializedFlowExecutionContinuation extends FlowExecutionContinuation impl compressed = in.readBoolean(); } - // internal helpers + // subclassing hooks /** * Return the flow execution data in its raw byte[] form. Will decompress if necessary. diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionContinuationFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionSnapshotFactory.java similarity index 57% rename from spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionContinuationFactory.java rename to spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionSnapshotFactory.java index d817e9cf..3ea9378f 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionContinuationFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SerializedFlowExecutionSnapshotFactory.java @@ -22,49 +22,48 @@ import java.io.ObjectInputStream; import org.springframework.webflow.execution.FlowExecution; /** - * A factory that creates new instances of flow execution continuations based on standard Java serialization. + * A factory that creates new instances of flow execution snapshots based on standard Java serialization. * * @author Keith Donald * @author Erwin Vervaet */ -public class SerializedFlowExecutionContinuationFactory implements FlowExecutionContinuationFactory { +public class SerializedFlowExecutionSnapshotFactory implements FlowExecutionSnapshotFactory { /** - * Flag to toggle continuation compression; compression is on by default. + * Flag to toggle snapshot compression; compression is on by default. */ private boolean compress = true; /** - * Returns whether or not the continuations should be compressed. + * Returns whether or not the snapshots should be compressed. */ public boolean getCompress() { return compress; } /** - * Set whether or not the continuations should be compressed. + * Set whether or not the snapshots should be compressed. */ public void setCompress(boolean compress) { this.compress = compress; } - public FlowExecutionContinuation createContinuation(FlowExecution flowExecution) - throws ContinuationCreationException { - return new SerializedFlowExecutionContinuation(flowExecution, compress); + public FlowExecutionSnapshot createSnapshot(FlowExecution flowExecution) throws SnapshotCreationException { + return new SerializedFlowExecutionSnapshot(flowExecution, compress); } - public FlowExecutionContinuation restoreContinuation(byte[] bytes) throws ContinuationUnmarshalException { + public FlowExecutionSnapshot restoreSnapshot(byte[] bytes) throws SnapshotUnmarshalException { try { ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes)); try { - return (FlowExecutionContinuation) ois.readObject(); + return (FlowExecutionSnapshot) ois.readObject(); } finally { ois.close(); } } catch (IOException e) { - throw new ContinuationUnmarshalException("IO problem while creating a flow execution continuation", e); + throw new SnapshotUnmarshalException("IO problem while creating the flow execution snapshot", e); } catch (ClassNotFoundException e) { - throw new ContinuationUnmarshalException("Class not found while creating a flow execution continuation", e); + throw new SnapshotUnmarshalException("Class not found while creating the flow execution snapshot", e); } } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/ContinuationCreationException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SnapshotCreationException.java similarity index 82% rename from spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/ContinuationCreationException.java rename to spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SnapshotCreationException.java index 1c94f059..d546cd2a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/ContinuationCreationException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SnapshotCreationException.java @@ -23,7 +23,7 @@ import org.springframework.webflow.execution.repository.FlowExecutionRepositoryE * * @author Keith Donald */ -public class ContinuationCreationException extends FlowExecutionRepositoryException { +public class SnapshotCreationException extends FlowExecutionRepositoryException { /** * The flow execution that could not be snapshotted. @@ -31,12 +31,12 @@ public class ContinuationCreationException extends FlowExecutionRepositoryExcept private FlowExecution flowExecution; /** - * Creates a new continuation creation exception. + * Creates a new snapshot creation exception. * @param flowExecution the flow execution * @param message a descriptive message * @param cause the cause */ - public ContinuationCreationException(FlowExecution flowExecution, String message, Throwable cause) { + public SnapshotCreationException(FlowExecution flowExecution, String message, Throwable cause) { super(message, cause); this.flowExecution = flowExecution; } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SnapshotNotFoundException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SnapshotNotFoundException.java new file mode 100644 index 00000000..85297fc6 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SnapshotNotFoundException.java @@ -0,0 +1,49 @@ +/* + * Copyright 2004-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.webflow.execution.repository.continuation; + +import java.io.Serializable; + +import org.springframework.webflow.execution.repository.FlowExecutionRepositoryException; + +/** + * Thrown when a flow execution snapshot cannot be found This usually occurs when the client references a snapshot that + * has since been removed. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class SnapshotNotFoundException extends FlowExecutionRepositoryException { + + private Serializable snapshotId; + + /** + * Creates a snapshot not found exception. + * @param snapshotId the snapshot id that could not be found + */ + public SnapshotNotFoundException(Serializable snapshotId) { + super("No flow execution snapshot could be found with id '" + snapshotId + + "'; perhaps the snapshot has been removed? "); + this.snapshotId = snapshotId; + } + + /** + * The id of the snapshot that was not found. + */ + public Serializable getSnapshotId() { + return snapshotId; + } +} \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/ContinuationUnmarshalException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SnapshotUnmarshalException.java similarity index 83% rename from spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/ContinuationUnmarshalException.java rename to spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SnapshotUnmarshalException.java index 72ed845f..bf96d70c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/ContinuationUnmarshalException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/continuation/SnapshotUnmarshalException.java @@ -21,19 +21,19 @@ import org.springframework.webflow.execution.repository.FlowExecutionRepositoryE /** * Thrown when a FlowExecutionContinuation could not be deserialized into a FlowExecution. * - * @see FlowExecutionContinuation + * @see FlowExecutionSnapshot * @see FlowExecution * * @author Keith Donald */ -public class ContinuationUnmarshalException extends FlowExecutionRepositoryException { +public class SnapshotUnmarshalException extends FlowExecutionRepositoryException { /** * Creates a new flow execution unmarshalling exception. * @param message the exception message * @param cause the cause */ - public ContinuationUnmarshalException(String message, Throwable cause) { + public SnapshotUnmarshalException(String message, Throwable cause) { super(message, cause); } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/DefaultFlowExecutionRepository.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/DefaultFlowExecutionRepository.java index 6af51ee2..95c39971 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/DefaultFlowExecutionRepository.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/DefaultFlowExecutionRepository.java @@ -20,94 +20,87 @@ import org.springframework.webflow.conversation.ConversationManager; import org.springframework.webflow.execution.FlowExecution; import org.springframework.webflow.execution.FlowExecutionKey; import org.springframework.webflow.execution.repository.FlowExecutionRestorationFailureException; -import org.springframework.webflow.execution.repository.continuation.AbstractFlowExecutionContinuationRepository; -import org.springframework.webflow.execution.repository.continuation.ContinuationNotFoundException; -import org.springframework.webflow.execution.repository.continuation.ContinuationUnmarshalException; -import org.springframework.webflow.execution.repository.continuation.FlowExecutionContinuation; -import org.springframework.webflow.execution.repository.continuation.FlowExecutionContinuationFactory; -import org.springframework.webflow.execution.repository.continuation.SerializedFlowExecutionContinuationFactory; +import org.springframework.webflow.execution.repository.continuation.AbstractSnapshottingFlowExecutionRepository; +import org.springframework.webflow.execution.repository.continuation.FlowExecutionSnapshot; +import org.springframework.webflow.execution.repository.continuation.FlowExecutionSnapshotFactory; +import org.springframework.webflow.execution.repository.continuation.SerializedFlowExecutionSnapshotFactory; +import org.springframework.webflow.execution.repository.continuation.SnapshotNotFoundException; +import org.springframework.webflow.execution.repository.continuation.SnapshotUnmarshalException; import org.springframework.webflow.execution.repository.support.FlowExecutionStateRestorer; /** - * Stores one to many flow execution continuations (snapshots) per conversation, where each continuation - * represents a paused, restorable view-state of a flow execution snapshotted at a point in time. + * The default flow execution repository implementation. Takes one to {@link #getMaxSnapshots() max} flow + * execution snapshots, where each snapshot represents a copy of a {@link FlowExecution} taken at a point in time. *
- * The set of active user conversations are managed by a {@link ConversationManager} implementation, which this - * repository delegates to. + * The set of active flow executions are managed by a {@link ConversationManager} implementation, which this repository + * delegates to. *
* This repository is responsible for: *
- * This repository implementation also provides support for conversation invalidation after completion, where - * once a logical conversation completes (by one of its FlowExecution's reaching an end state), the entire conversation - * (including all continuations) is invalidated. This prevents the possibility of duplicate submission after completion. - *
- * This repository implementation should be considered when you do have to support browser navigational button use, e.g.
- * you cannot lock down the browser and require that all navigational events to be routed explicitly through Spring Web
- * Flow.
+ * This repository implementation also provides support for execution invalidation after completion, where once
+ * a logical flow execution completes, it and all of its snapshots are removed. This cleans up memory and prevents the
+ * possibility of duplicate submission after completion.
*
* @author Keith Donald
*/
-public class DefaultFlowExecutionRepository extends AbstractFlowExecutionContinuationRepository {
+public class DefaultFlowExecutionRepository extends AbstractSnapshottingFlowExecutionRepository {
/**
- * The conversation attribute that stores the "continuation group".
+ * The conversation attribute that stores the group of flow execution snapshots.
*/
- private static final String CONTINUATION_GROUP_ATTRIBUTE = "continuationGroup";
+ private static final String SNAPSHOT_GROUP_ATTRIBUTE = "flowExecutionSnapshotGroup";
/**
- * The maximum number of continuations that can be active per conversation. The default is 30, which is high enough
- * not to interfere with the user experience of normal users using the back button, but low enough to avoid
- * excessive resource usage or easy denial of service attacks.
+ * The maximum number of snapshots that can be taken per execution. The default is 30, which is generally high
+ * enough not to interfere with the user experience of normal users using the back button, but low enough to avoid
+ * excessive resource usage or denial of service attacks.
*/
- private int maxContinuations = 30;
+ private int maxSnapshots = 30;
/**
- * Create a new continuation based flow execution repository using the given state restorer and conversation
- * manager. Defaults to a {@link SerializedFlowExecutionContinuationFactory}.
+ * Create a new default flow execution repository using the given state restorer and conversation manager. Defaults
+ * to a {@link SerializedFlowExecutionSnapshotFactory}.
* @param conversationManager the conversation manager to use
* @param executionStateRestorer the state restoration strategy to use
*/
public DefaultFlowExecutionRepository(ConversationManager conversationManager,
FlowExecutionStateRestorer executionStateRestorer) {
- super(conversationManager, executionStateRestorer, new SerializedFlowExecutionContinuationFactory());
+ super(conversationManager, executionStateRestorer, new SerializedFlowExecutionSnapshotFactory());
}
/**
- * Create a new continuation based flow execution repository using the given state restorer, conversation manager,
- * and continuation factory.
+ * Create a new default flow execution repository using the given state restorer, conversation manager, and snapshot
+ * factory.
* @param conversationManager the conversation manager to use
* @param executionStateRestorer the state restoration strategy to use
- * @param continuationFactory the continuation factory to use
+ * @param executionSnapshotFactory the flow execution snapshot factory to use
*/
public DefaultFlowExecutionRepository(ConversationManager conversationManager,
- FlowExecutionStateRestorer executionStateRestorer, FlowExecutionContinuationFactory continuationFactory) {
- super(conversationManager, executionStateRestorer, continuationFactory);
+ FlowExecutionStateRestorer executionStateRestorer, FlowExecutionSnapshotFactory executionSnapshotFactory) {
+ super(conversationManager, executionStateRestorer, executionSnapshotFactory);
}
/**
- * Returns the max number of continuations allowed per conversation by this repository.
+ * Returns the max number of snapshots allowed per flow execution by this repository.
*/
- public int getMaxContinuations() {
- return maxContinuations;
+ public int getMaxSnapshots() {
+ return maxSnapshots;
}
/**
- * Sets the maximum number of continuations allowed per conversation by this repository. Use -1 for unlimited. The
+ * Sets the maximum number of snapshots allowed per flow execution by this repository. Use -1 for unlimited. The
* default is 30.
*/
- public void setMaxContinuations(int maxContinuations) {
- this.maxContinuations = maxContinuations;
+ public void setMaxSnapshots(int maxSnapshots) {
+ this.maxSnapshots = maxSnapshots;
}
// implementing flow execution repository
@@ -117,16 +110,16 @@ public class DefaultFlowExecutionRepository extends AbstractFlowExecutionContinu
logger.debug("Getting flow execution with key '" + key + "'");
}
Conversation conversation = getConversation(key);
- FlowExecutionContinuation snapshot;
+ FlowExecutionSnapshot snapshot;
try {
- snapshot = getContinuationGroup(conversation).get(getContinuationId(key));
- } catch (ContinuationNotFoundException e) {
+ snapshot = getSnapshotGroup(conversation).getSnapshot(getSnapshotId(key));
+ } catch (SnapshotNotFoundException e) {
throw new FlowExecutionRestorationFailureException(key, e);
}
try {
FlowExecution execution = snapshot.unmarshal();
return restoreTransientState(execution, key, conversation);
- } catch (ContinuationUnmarshalException e) {
+ } catch (SnapshotUnmarshalException e) {
throw new FlowExecutionRestorationFailureException(key, e);
}
}
@@ -138,12 +131,12 @@ public class DefaultFlowExecutionRepository extends AbstractFlowExecutionContinu
}
FlowExecutionKey key = flowExecution.getKey();
Conversation conversation = getConversation(key);
- FlowExecutionContinuationGroup continuationGroup = getContinuationGroup(conversation);
- FlowExecutionContinuation snapshot = snapshot(flowExecution);
+ FlowExecutionSnapshotGroup snapshotGroup = getSnapshotGroup(conversation);
+ FlowExecutionSnapshot snapshot = snapshot(flowExecution);
if (logger.isDebugEnabled()) {
- logger.debug("Adding new snapshot to group with id " + getContinuationId(key));
+ logger.debug("Adding new snapshot to group with id " + getSnapshotId(key));
}
- continuationGroup.add(getContinuationId(key), snapshot);
+ snapshotGroup.addSnapshot(getSnapshotId(key), snapshot);
putConversationScope(flowExecution, conversation);
}
@@ -151,38 +144,40 @@ public class DefaultFlowExecutionRepository extends AbstractFlowExecutionContinu
public void removeAllFlowExecutionSnapshots(FlowExecution execution) {
Conversation conversation = getConversation(execution.getKey());
- getContinuationGroup(conversation).removeAllContinuations();
+ getSnapshotGroup(conversation).removeAllSnapshots();
}
public void removeFlowExecutionSnapshot(FlowExecution execution) {
FlowExecutionKey key = execution.getKey();
Conversation conversation = getConversation(key);
- getContinuationGroup(conversation).removeContinuation(getContinuationId(key));
+ getSnapshotGroup(conversation).removeSnapshot(getSnapshotId(key));
}
public void updateFlowExecutionSnapshot(FlowExecution execution) {
FlowExecutionKey key = execution.getKey();
Conversation conversation = getConversation(key);
- getContinuationGroup(conversation).updateContinuation(getContinuationId(key), snapshot(execution));
+ getSnapshotGroup(conversation).updateSnapshot(getSnapshotId(key), snapshot(execution));
}
// hooks for subclassing
- protected FlowExecutionContinuationGroup createFlowExecutionContinuationGroup() {
- return new FlowExecutionContinuationGroup(maxContinuations);
+ protected FlowExecutionSnapshotGroup createFlowExecutionSnapshotGroup() {
+ SimpleFlowExecutionSnapshotGroup group = new SimpleFlowExecutionSnapshotGroup();
+ group.setMaxSnapshots(maxSnapshots);
+ return group;
}
/**
- * Returns the continuation group associated with the governing conversation.
- * @param conversation the conversation where the continuation group is stored
- * @return the continuation group
+ * Returns the snapshot group associated with the governing conversation.
+ * @param conversation the conversation where the snapshot group is stored
+ * @return the snapshot group
*/
- protected FlowExecutionContinuationGroup getContinuationGroup(Conversation conversation) {
- FlowExecutionContinuationGroup group = (FlowExecutionContinuationGroup) conversation
- .getAttribute(CONTINUATION_GROUP_ATTRIBUTE);
+ protected FlowExecutionSnapshotGroup getSnapshotGroup(Conversation conversation) {
+ FlowExecutionSnapshotGroup group = (FlowExecutionSnapshotGroup) conversation
+ .getAttribute(SNAPSHOT_GROUP_ATTRIBUTE);
if (group == null) {
- group = createFlowExecutionContinuationGroup();
- conversation.putAttribute(CONTINUATION_GROUP_ATTRIBUTE, group);
+ group = createFlowExecutionSnapshotGroup();
+ conversation.putAttribute(SNAPSHOT_GROUP_ATTRIBUTE, group);
}
return group;
}
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/FlowExecutionContinuationGroup.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/FlowExecutionContinuationGroup.java
deleted file mode 100644
index b66010e1..00000000
--- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/FlowExecutionContinuationGroup.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2004-2008 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.webflow.execution.repository.impl;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-
-import org.springframework.webflow.execution.repository.continuation.ContinuationNotFoundException;
-import org.springframework.webflow.execution.repository.continuation.FlowExecutionContinuation;
-
-/**
- * A group of flow execution continuations. Simple typed data structure backed by a map and linked list. Supports
- * expelling the oldest continuation once a maximum group size is met.
- *
- * @author Keith Donald
- */
-class FlowExecutionContinuationGroup implements Serializable {
-
- /**
- * A map of continuations; the key is the continuation id, and the value is the {@link FlowExecutionContinuation}
- * object.
- */
- private Map continuations = new HashMap();
-
- /**
- * An ordered list of continuation ids. Each continuation id represents an pointer to a continuation in the map. The
- * first element is the oldest continuation and the last is the youngest.
- */
- private LinkedList continuationIds = new LinkedList();
-
- /**
- * The maximum number of continuations allowed in this group.
- */
- private int maxContinuations = -1;
-
- /**
- * Creates a new flow execution continuation group.
- * @param maxContinuations the maximum number of continuations that can be stored in this group, -1 for unlimited
- */
- public FlowExecutionContinuationGroup(int maxContinuations) {
- this.maxContinuations = maxContinuations;
- }
-
- /**
- * Returns the count of continuations in this group.
- */
- public int getContinuationCount() {
- return continuationIds.size();
- }
-
- /**
- * Returns the continuation with the provided id, or null if no such continuation
- * exists with that id.
- * @param continuationId the continuation id
- * @return the continuation
- * @throws ContinuationNotFoundException if the id does not match a continuation in this group
- */
- public FlowExecutionContinuation get(Serializable continuationId) throws ContinuationNotFoundException {
- FlowExecutionContinuation continuation = (FlowExecutionContinuation) continuations.get(continuationId);
- if (continuation == null) {
- throw new ContinuationNotFoundException(continuationId);
- }
- return continuation;
- }
-
- /**
- * Add a flow execution continuation with given id to this group.
- * @param continuationId the continuation id
- * @param continuation the continuation
- */
- public void add(Serializable continuationId, FlowExecutionContinuation continuation) {
- continuations.put(continuationId, continuation);
- if (continuationIds.contains(continuationId)) {
- continuationIds.remove(continuationId);
- }
- continuationIds.add(continuationId);
- // remove the oldest continuation if the maximium number of
- // continuations has been exceeded
- if (maxExceeded()) {
- removeOldestContinuation();
- }
- }
-
- /**
- * Update the continuation with the given id.
- * @param continuationId the continuation id
- * @param continuation thew new continuation
- * @throws ContinuationNotFoundException if there was no previous continuation to update
- */
- public void updateContinuation(Serializable continuationId, FlowExecutionContinuation continuation)
- throws ContinuationNotFoundException {
- if (!continuations.containsKey(continuationId)) {
- throw new ContinuationNotFoundException(continuationId);
- }
- continuations.put(continuationId, continuation);
- }
-
- /**
- * Remove the continuation with the given id.
- * @param continuationId the continuation id
- */
- public void removeContinuation(Serializable continuationId) {
- continuations.remove(continuationId);
- continuationIds.remove(continuationId);
- }
-
- /**
- * Remove all continuations in this group.
- */
- public void removeAllContinuations() {
- continuations.clear();
- continuationIds.clear();
- }
-
- /**
- * Has the maximum number of allowed continuations in this group been exceeded?
- */
- private boolean maxExceeded() {
- return maxContinuations > 0 && continuationIds.size() > maxContinuations;
- }
-
- /**
- * Remove the olders continuation from this group.
- */
- private void removeOldestContinuation() {
- continuations.remove(continuationIds.removeFirst());
- }
-
-}
\ No newline at end of file
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/FlowExecutionSnapshotGroup.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/FlowExecutionSnapshotGroup.java
new file mode 100644
index 00000000..497ce29b
--- /dev/null
+++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/FlowExecutionSnapshotGroup.java
@@ -0,0 +1,56 @@
+package org.springframework.webflow.execution.repository.impl;
+
+import java.io.Serializable;
+
+import org.springframework.webflow.execution.repository.continuation.FlowExecutionSnapshot;
+import org.springframework.webflow.execution.repository.continuation.SnapshotNotFoundException;
+
+/**
+ * A group of flow execution snapshots.
+ *
+ * @author Keith Donald
+ */
+public interface FlowExecutionSnapshotGroup {
+
+ /**
+ * Returns the snapshot with the provided id, or null if no such snapshot exists with
+ * that id.
+ * @param snapshotId the snapshot id
+ * @return the continuation
+ * @throws SnapshotNotFoundException if the id does not match a continuation in this group
+ */
+ public FlowExecutionSnapshot getSnapshot(Serializable snapshotId) throws SnapshotNotFoundException;
+
+ /**
+ * Add a flow execution snapshot with given id to this group.
+ * @param snapshotId the snapshot id
+ * @param snapshot the snapshot
+ */
+ public void addSnapshot(Serializable snapshotId, FlowExecutionSnapshot snapshot);
+
+ /**
+ * Update the snapshot with the given id.
+ * @param snapshotId the snapshot id
+ * @param snapshot the new snapshot
+ * @throws SnapshotNotFoundException if there was no previous snapshot to update
+ */
+ public void updateSnapshot(Serializable snapshotId, FlowExecutionSnapshot snapshot)
+ throws SnapshotNotFoundException;
+
+ /**
+ * Remove the snapshot with the given id.
+ * @param snapshotId the continuation id
+ */
+ public void removeSnapshot(Serializable snapshotId);
+
+ /**
+ * Remove all snapshots in this group.
+ */
+ public void removeAllSnapshots();
+
+ /**
+ * Returns the count of snapshots in this group.
+ */
+ public int getSnapshotCount();
+
+}
\ No newline at end of file
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/SimpleFlowExecutionSnapshotGroup.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/SimpleFlowExecutionSnapshotGroup.java
new file mode 100644
index 00000000..d51bdded
--- /dev/null
+++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/impl/SimpleFlowExecutionSnapshotGroup.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2004-2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.webflow.execution.repository.impl;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.springframework.webflow.execution.repository.continuation.FlowExecutionSnapshot;
+import org.springframework.webflow.execution.repository.continuation.SnapshotNotFoundException;
+
+/**
+ * A group of flow execution snapshots. Simple typed data structure backed by a map and linked list. Supports expelling
+ * the oldest snapshot if the maximum size is met.
+ *
+ * @author Keith Donald
+ */
+class SimpleFlowExecutionSnapshotGroup implements FlowExecutionSnapshotGroup, Serializable {
+
+ /**
+ * The snapshot map; the key is a snapshot id, and the value is a {@link FlowExecutionSnapshot} object.
+ */
+ private Map snapshots = new HashMap();
+
+ /**
+ * An ordered list of snapshot ids. Each snapshot id represents an pointer to a {@link FlowExecutionSnapshot} in the
+ * map. The first element is the oldest snapshot and the last is the youngest.
+ */
+ private LinkedList snapshotIds = new LinkedList();
+
+ /**
+ * The maximum number of snapshots allowed in this group.
+ */
+ private int maxSnapshots = -1;
+
+ /**
+ * Returns the maximum number of snapshots allowed in this group.
+ */
+ public int getMaxSnapshots() {
+ return maxSnapshots;
+ }
+
+ /**
+ * Sets the maximum number of snapshots allowed in this group.
+ * @param maxSnapshots them max number of snapshots
+ */
+ public void setMaxSnapshots(int maxSnapshots) {
+ this.maxSnapshots = maxSnapshots;
+ }
+
+ public FlowExecutionSnapshot getSnapshot(Serializable snapshotId) throws SnapshotNotFoundException {
+ FlowExecutionSnapshot snapshot = (FlowExecutionSnapshot) snapshots.get(snapshotId);
+ if (snapshot == null) {
+ throw new SnapshotNotFoundException(snapshotId);
+ }
+ return snapshot;
+ }
+
+ public void addSnapshot(Serializable snapshotId, FlowExecutionSnapshot snapshot) {
+ snapshots.put(snapshotId, snapshot);
+ if (snapshotIds.contains(snapshotId)) {
+ snapshotIds.remove(snapshotId);
+ }
+ snapshotIds.add(snapshotId);
+ if (maxExceeded()) {
+ removeOldestSnapshot();
+ }
+ }
+
+ public void updateSnapshot(Serializable snapshotId, FlowExecutionSnapshot snapshot)
+ throws SnapshotNotFoundException {
+ if (!snapshots.containsKey(snapshotId)) {
+ throw new SnapshotNotFoundException(snapshotId);
+ }
+ snapshots.put(snapshotId, snapshot);
+ }
+
+ public void removeSnapshot(Serializable snapshotId) {
+ snapshots.remove(snapshotId);
+ snapshotIds.remove(snapshotId);
+ }
+
+ public void removeAllSnapshots() {
+ snapshots.clear();
+ snapshotIds.clear();
+ }
+
+ public int getSnapshotCount() {
+ return snapshotIds.size();
+ }
+
+ /**
+ * Has the maximum number of snapshots in this group been exceeded?
+ */
+ private boolean maxExceeded() {
+ return maxSnapshots > 0 && snapshotIds.size() > maxSnapshots;
+ }
+
+ /**
+ * Remove the olders snapshot from this group.
+ */
+ private void removeOldestSnapshot() {
+ snapshots.remove(snapshotIds.removeFirst());
+ }
+
+}
\ No newline at end of file
diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/AbstractFlowExecutionRepository.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/AbstractFlowExecutionRepository.java
index 37c6f767..564b3416 100644
--- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/AbstractFlowExecutionRepository.java
+++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/AbstractFlowExecutionRepository.java
@@ -46,7 +46,7 @@ import org.springframework.webflow.execution.repository.NoSuchFlowExecutionExcep
* rehydrate a flow execution after it has been obtained from storage from resume.
*
* The configured {@link FlowExecutionStateRestorer} should be compatible with the chosen {@link FlowExecution} - * implementation and is configuration as done by a {@link FlowExecutionFactory} (listeners, execution attributes, ...). + * implementation and its {@link FlowExecutionFactory}. * * @author Keith Donald * @author Erwin Vervaet @@ -122,14 +122,9 @@ public abstract class AbstractFlowExecutionRepository implements FlowExecutionRe "The string-encoded flow execution key is required"); } String[] keyParts = CompositeFlowExecutionKey.keyParts(encodedKey); - ConversationId conversationId; - try { - conversationId = conversationManager.parseConversationId(keyParts[0]); - } catch (ConversationException e) { - throw new BadlyFormattedFlowExecutionKeyException(encodedKey, CompositeFlowExecutionKey.getFormat(), e); - } - Serializable continuationId = parseContinuationId(keyParts[1], encodedKey); - return new CompositeFlowExecutionKey(conversationId, continuationId); + Serializable executionId = parseExecutionId(keyParts[0], encodedKey); + Serializable snapshotId = parseSnapshotId(keyParts[1], encodedKey); + return new CompositeFlowExecutionKey(executionId, snapshotId); } public FlowExecutionLock getLock(FlowExecutionKey key) throws FlowExecutionRepositoryException { @@ -170,10 +165,9 @@ public abstract class AbstractFlowExecutionRepository implements FlowExecutionRe */ protected FlowExecutionKey getNextKey(FlowExecution execution) { if (alwaysGenerateNewNextKey) { - CompositeFlowExecutionKey key = (CompositeFlowExecutionKey) execution.getKey(); - Integer continuationId = (Integer) key.getContinuationId(); - Integer nextId = nextContinuationId(continuationId); - return new CompositeFlowExecutionKey(key.getConversationId(), nextId); + CompositeFlowExecutionKey currentKey = (CompositeFlowExecutionKey) execution.getKey(); + Integer currentSnapshotId = (Integer) currentKey.getSnapshotId(); + return new CompositeFlowExecutionKey(currentKey.getExecutionId(), nextSnapshotId(currentSnapshotId)); } else { return execution.getKey(); } @@ -187,28 +181,13 @@ public abstract class AbstractFlowExecutionRepository implements FlowExecutionRe */ protected Conversation getConversation(FlowExecutionKey key) throws NoSuchFlowExecutionException { try { - return conversationManager.getConversation(getConversationId(key)); + ConversationId conversationId = (ConversationId) ((CompositeFlowExecutionKey) key).getExecutionId(); + return conversationManager.getConversation(conversationId); } catch (NoSuchConversationException e) { throw new NoSuchFlowExecutionException(key, e); } } - /** - * Returns the conversationId portion of the flow execution key. - * @param key the execution key - */ - protected ConversationId getConversationId(FlowExecutionKey key) { - return ((CompositeFlowExecutionKey) key).getConversationId(); - } - - /** - * Returns the continuationId portion of the flow execution key. - * @param key the execution key - */ - protected Serializable getContinuationId(FlowExecutionKey key) { - return ((CompositeFlowExecutionKey) key).getContinuationId(); - } - /** * Returns the transient state of the flow execution after potential deserialization. * @param execution the flow execution @@ -251,15 +230,25 @@ public abstract class AbstractFlowExecutionRepository implements FlowExecutionRe return conversation; } - private Integer nextContinuationId(Integer continuationId) { + private Integer nextSnapshotId(Integer currentSnapshotId) { if (JdkVersion.isAtLeastJava15()) { - return Integer.valueOf(continuationId.intValue() + 1); + return Integer.valueOf(currentSnapshotId.intValue() + 1); } else { - return new Integer(continuationId.intValue() + 1); + return new Integer(currentSnapshotId.intValue() + 1); } } - private Serializable parseContinuationId(String encodedId, String encodedKey) { + private ConversationId parseExecutionId(String encodedId, String encodedKey) + throws BadlyFormattedFlowExecutionKeyException { + try { + return conversationManager.parseConversationId(encodedId); + } catch (ConversationException e) { + throw new BadlyFormattedFlowExecutionKeyException(encodedKey, CompositeFlowExecutionKey.getFormat(), e); + } + } + + private Serializable parseSnapshotId(String encodedId, String encodedKey) + throws BadlyFormattedFlowExecutionKeyException { try { return Integer.valueOf(encodedId); } catch (NumberFormatException e) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/CompositeFlowExecutionKey.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/CompositeFlowExecutionKey.java index c3b4231c..7314e543 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/CompositeFlowExecutionKey.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/CompositeFlowExecutionKey.java @@ -18,79 +18,54 @@ package org.springframework.webflow.execution.repository.support; import java.io.Serializable; import org.springframework.util.Assert; -import org.springframework.webflow.conversation.ConversationId; -import org.springframework.webflow.conversation.ConversationManager; +import org.springframework.webflow.execution.FlowExecution; import org.springframework.webflow.execution.FlowExecutionKey; import org.springframework.webflow.execution.repository.BadlyFormattedFlowExecutionKeyException; -import org.springframework.webflow.execution.repository.continuation.FlowExecutionContinuation; /** - * A flow execution key consisting of two parts: + * A flow execution key that consists of two parts: *
- * This key is used to restore a FlowExecution from a conversation-service backed store.
- *
- * @see ConversationManager
- * @see FlowExecutionContinuation
- *
* @author Keith Donald
*/
public class CompositeFlowExecutionKey extends FlowExecutionKey {
- /**
- * The default conversation id prefix delimiter.
- */
- private static final String CONVERSATION_ID_PREFIX = "c";
+ private static final String EXECUTION_ID_PREFIX = "e";
- /**
- * The default continuation id prefix delimiter.
- */
- private static final String CONTINUATION_ID_PREFIX = "v";
+ private static final String SNAPSHOT_ID_PREFIX = "s";
- /**
- * The format of the default string-encoded form, as returned by toString().
- */
- private static final String FORMAT = CONVERSATION_ID_PREFIX + "