diff --git a/spring-binding/src/main/java/org/springframework/binding/collection/SharedMap.java b/spring-binding/src/main/java/org/springframework/binding/collection/SharedMap.java index 108bd0d7..a0660ba6 100644 --- a/spring-binding/src/main/java/org/springframework/binding/collection/SharedMap.java +++ b/spring-binding/src/main/java/org/springframework/binding/collection/SharedMap.java @@ -1,45 +1,45 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.binding.collection; - -import java.util.Map; - -/** - * A simple subinterface of {@link Map} that exposes a mutex that application code can synchronize on. - *

- * Expected to be implemented by Maps that are backed by shared objects that require synchronization between multiple - * threads. An example would be the HTTP session map. - * - * @author Keith Donald - */ -public interface SharedMap extends Map { - - /** - * Returns the shared mutex that may be synchronized on using a synchronized block. The returned mutex is guaranteed - * to be non-null. - * - * Example usage: - * - *

-	 * synchronized (sharedMap.getMutex()) {
-	 * 	// do synchronized work
-	 * }
-	 * 
- * - * @return the mutex - */ - Object getMutex(); -} +/* + * Copyright 2004-2012 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 + * + * https://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.binding.collection; + +import java.util.Map; + +/** + * A simple subinterface of {@link Map} that exposes a mutex that application code can synchronize on. + *

+ * Expected to be implemented by Maps that are backed by shared objects that require synchronization between multiple + * threads. An example would be the HTTP session map. + * + * @author Keith Donald + */ +public interface SharedMap extends Map { + + /** + * Returns the shared mutex that may be synchronized on using a synchronized block. The returned mutex is guaranteed + * to be non-null. + * + * Example usage: + * + *

+	 * synchronized (sharedMap.getMutex()) {
+	 * 	// do synchronized work
+	 * }
+	 * 
+ * + * @return the mutex + */ + Object getMutex(); +} diff --git a/spring-binding/src/main/java/org/springframework/binding/collection/SharedMapDecorator.java b/spring-binding/src/main/java/org/springframework/binding/collection/SharedMapDecorator.java index b0e084b1..dfae6881 100644 --- a/spring-binding/src/main/java/org/springframework/binding/collection/SharedMapDecorator.java +++ b/spring-binding/src/main/java/org/springframework/binding/collection/SharedMapDecorator.java @@ -1,105 +1,105 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.binding.collection; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Map; -import java.util.Set; - -import org.springframework.core.style.ToStringCreator; - -/** - * A map decorator that implements SharedMap. By default, simply returns the map itself as the mutex. - * Subclasses may override to return a different mutex object. - * - * @author Keith Donald - */ -public class SharedMapDecorator implements SharedMap, Serializable { - - /** - * The wrapped, target map. - */ - private Map map; - - /** - * Creates a new shared map decorator. - * @param map the map that is shared by multiple threads, to be synced - */ - public SharedMapDecorator(Map map) { - this.map = map; - } - - // implementing Map - - public void clear() { - map.clear(); - } - - public boolean containsKey(Object key) { - return map.containsKey(key); - } - - public boolean containsValue(Object value) { - return map.containsValue(value); - } - - public Set> entrySet() { - return map.entrySet(); - } - - public V get(Object key) { - return map.get(key); - } - - public boolean isEmpty() { - return map.isEmpty(); - } - - public Set keySet() { - return map.keySet(); - } - - public V put(K key, V value) { - return map.put(key, value); - } - - public void putAll(Map map) { - this.map.putAll(map); - } - - public V remove(Object key) { - return map.remove(key); - } - - public int size() { - return map.size(); - } - - public Collection values() { - return map.values(); - } - - // implementing SharedMap - - public Object getMutex() { - return map; - } - - public String toString() { - return new ToStringCreator(this).append("map", map).append("mutex", getMutex()).toString(); - } +/* + * Copyright 2004-2012 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 + * + * https://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.binding.collection; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import org.springframework.core.style.ToStringCreator; + +/** + * A map decorator that implements SharedMap. By default, simply returns the map itself as the mutex. + * Subclasses may override to return a different mutex object. + * + * @author Keith Donald + */ +public class SharedMapDecorator implements SharedMap, Serializable { + + /** + * The wrapped, target map. + */ + private Map map; + + /** + * Creates a new shared map decorator. + * @param map the map that is shared by multiple threads, to be synced + */ + public SharedMapDecorator(Map map) { + this.map = map; + } + + // implementing Map + + public void clear() { + map.clear(); + } + + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + public Set> entrySet() { + return map.entrySet(); + } + + public V get(Object key) { + return map.get(key); + } + + public boolean isEmpty() { + return map.isEmpty(); + } + + public Set keySet() { + return map.keySet(); + } + + public V put(K key, V value) { + return map.put(key, value); + } + + public void putAll(Map map) { + this.map.putAll(map); + } + + public V remove(Object key) { + return map.remove(key); + } + + public int size() { + return map.size(); + } + + public Collection values() { + return map.values(); + } + + // implementing SharedMap + + public Object getMutex() { + return map; + } + + public String toString() { + return new ToStringCreator(this).append("map", map).append("mutex", getMutex()).toString(); + } } diff --git a/spring-binding/src/main/java/org/springframework/binding/collection/StringKeyedMapAdapter.java b/spring-binding/src/main/java/org/springframework/binding/collection/StringKeyedMapAdapter.java index eb594e91..d11079c7 100644 --- a/spring-binding/src/main/java/org/springframework/binding/collection/StringKeyedMapAdapter.java +++ b/spring-binding/src/main/java/org/springframework/binding/collection/StringKeyedMapAdapter.java @@ -1,289 +1,289 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.binding.collection; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; - -/** - * Base class for map adapters whose keys are String values. Concrete classes need only implement the abstract hook - * methods defined by this class. - * - * @author Keith Donald - */ -public abstract class StringKeyedMapAdapter implements Map { - - private Set keySet; - - private Collection values; - - private Set> entrySet; - - // implementing Map - - public void clear() { - for (Iterator it = getAttributeNames(); it.hasNext();) { - removeAttribute(it.next()); - } - } - - public boolean containsKey(Object key) { - return getAttribute(key.toString()) != null; - } - - public boolean containsValue(Object value) { - if (value == null) { - return false; - } - for (Iterator it = getAttributeNames(); it.hasNext();) { - Object aValue = getAttribute(it.next()); - if (value.equals(aValue)) { - return true; - } - } - return false; - } - - public Set> entrySet() { - return (entrySet != null) ? entrySet : (entrySet = new EntrySet()); - } - - public V get(Object key) { - return getAttribute(key.toString()); - } - - public boolean isEmpty() { - return !getAttributeNames().hasNext(); - } - - public Set keySet() { - return (keySet != null) ? keySet : (keySet = new KeySet()); - } - - public V put(String key, V value) { - String stringKey = String.valueOf(key); - V previousValue = getAttribute(stringKey); - setAttribute(stringKey, value); - return previousValue; - } - - public void putAll(Map map) { - for (Entry entry : map.entrySet()) { - setAttribute(entry.getKey(), entry.getValue()); - } - } - - public V remove(Object key) { - String stringKey = key.toString(); - V retval = getAttribute(stringKey); - removeAttribute(stringKey); - return retval; - } - - public int size() { - int size = 0; - for (Iterator it = getAttributeNames(); it.hasNext();) { - size++; - it.next(); - } - return size; - } - - public Collection values() { - return (values != null) ? values : (values = new Values()); - } - - // hook methods - - /** - * Hook method that needs to be implemented by concrete subclasses. Gets a value associated with a key. - * @param key the key to lookup - * @return the associated value, or null if none - */ - protected abstract V getAttribute(String key); - - /** - * Hook method that needs to be implemented by concrete subclasses. Puts a key-value pair in the map, overwriting - * any possible earlier value associated with the same key. - * @param key the key to associate the value with - * @param value the value to associate with the key - */ - protected abstract void setAttribute(String key, V value); - - /** - * Hook method that needs to be implemented by concrete subclasses. Removes a key and its associated value from the - * map. - * @param key the key to remove - */ - protected abstract void removeAttribute(String key); - - /** - * Hook method that needs to be implemented by concrete subclasses. Returns an enumeration listing all keys known to - * the map. - * @return the key enumeration - */ - protected abstract Iterator getAttributeNames(); - - // internal helper classes - - private abstract class AbstractSet extends java.util.AbstractSet { - public boolean isEmpty() { - return StringKeyedMapAdapter.this.isEmpty(); - } - - public int size() { - return StringKeyedMapAdapter.this.size(); - } - - public void clear() { - StringKeyedMapAdapter.this.clear(); - } - } - - private class KeySet extends AbstractSet { - public Iterator iterator() { - return new KeyIterator(); - } - - public boolean contains(Object o) { - return StringKeyedMapAdapter.this.containsKey(o); - } - - public boolean remove(Object o) { - return StringKeyedMapAdapter.this.remove(o) != null; - } - } - - private abstract class AbstractKeyIterator { - private final Iterator it = getAttributeNames(); - - private String currentKey; - - public void remove() { - if (currentKey == null) { - throw new NoSuchElementException("You must call next() at least once"); - } - StringKeyedMapAdapter.this.remove(currentKey); - } - - public boolean hasNext() { - return it.hasNext(); - } - - protected String nextKey() { - return currentKey = it.next(); - } - } - - private class KeyIterator extends AbstractKeyIterator implements Iterator { - public String next() { - return nextKey(); - } - } - - private class Values extends AbstractSet { - public Iterator iterator() { - return new ValuesIterator(); - } - - public boolean contains(Object o) { - return StringKeyedMapAdapter.this.containsValue(o); - } - - public boolean remove(Object o) { - if (o == null) { - return false; - } - for (Iterator it = iterator(); it.hasNext();) { - if (o.equals(it.next())) { - it.remove(); - return true; - } - } - return false; - } - } - - private class ValuesIterator extends AbstractKeyIterator implements Iterator { - public V next() { - return StringKeyedMapAdapter.this.get(nextKey()); - } - } - - private class EntrySet extends AbstractSet> { - public Iterator> iterator() { - return new EntryIterator(); - } - - public boolean contains(Object o) { - Entry entry = getAsEntry(o); - if (entry == null || entry.getKey() == null || entry.getValue() == null) { - return false; - } - V valueFromThisMap = StringKeyedMapAdapter.this.get(entry.getKey()); - return entry.getValue().equals(valueFromThisMap); - } - - public boolean remove(Object o) { - Entry entry = getAsEntry(o); - if (entry == null || entry.getKey() == null || entry.getValue() == null) { - return false; - } - V valueFromThisMap = StringKeyedMapAdapter.this.get(entry.getKey()); - if (!entry.getValue().equals(valueFromThisMap)) { - return false; - } - return StringKeyedMapAdapter.this.remove(entry.getKey()) != null; - } - - @SuppressWarnings("unchecked") - private Entry getAsEntry(Object o) { - if (o instanceof Entry) { - return (Entry) o; - } - return null; - } - } - - private class EntryIterator extends AbstractKeyIterator implements Iterator> { - public Entry next() { - return new EntrySetEntry(nextKey()); - } - } - - private class EntrySetEntry implements Entry { - private final String currentKey; - - public EntrySetEntry(String currentKey) { - this.currentKey = currentKey; - } - - public String getKey() { - return currentKey; - } - - public V getValue() { - return StringKeyedMapAdapter.this.get(currentKey); - } - - public V setValue(V value) { - return StringKeyedMapAdapter.this.put(currentKey, value); - } - } +/* + * Copyright 2004-2012 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 + * + * https://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.binding.collection; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * Base class for map adapters whose keys are String values. Concrete classes need only implement the abstract hook + * methods defined by this class. + * + * @author Keith Donald + */ +public abstract class StringKeyedMapAdapter implements Map { + + private Set keySet; + + private Collection values; + + private Set> entrySet; + + // implementing Map + + public void clear() { + for (Iterator it = getAttributeNames(); it.hasNext();) { + removeAttribute(it.next()); + } + } + + public boolean containsKey(Object key) { + return getAttribute(key.toString()) != null; + } + + public boolean containsValue(Object value) { + if (value == null) { + return false; + } + for (Iterator it = getAttributeNames(); it.hasNext();) { + Object aValue = getAttribute(it.next()); + if (value.equals(aValue)) { + return true; + } + } + return false; + } + + public Set> entrySet() { + return (entrySet != null) ? entrySet : (entrySet = new EntrySet()); + } + + public V get(Object key) { + return getAttribute(key.toString()); + } + + public boolean isEmpty() { + return !getAttributeNames().hasNext(); + } + + public Set keySet() { + return (keySet != null) ? keySet : (keySet = new KeySet()); + } + + public V put(String key, V value) { + String stringKey = String.valueOf(key); + V previousValue = getAttribute(stringKey); + setAttribute(stringKey, value); + return previousValue; + } + + public void putAll(Map map) { + for (Entry entry : map.entrySet()) { + setAttribute(entry.getKey(), entry.getValue()); + } + } + + public V remove(Object key) { + String stringKey = key.toString(); + V retval = getAttribute(stringKey); + removeAttribute(stringKey); + return retval; + } + + public int size() { + int size = 0; + for (Iterator it = getAttributeNames(); it.hasNext();) { + size++; + it.next(); + } + return size; + } + + public Collection values() { + return (values != null) ? values : (values = new Values()); + } + + // hook methods + + /** + * Hook method that needs to be implemented by concrete subclasses. Gets a value associated with a key. + * @param key the key to lookup + * @return the associated value, or null if none + */ + protected abstract V getAttribute(String key); + + /** + * Hook method that needs to be implemented by concrete subclasses. Puts a key-value pair in the map, overwriting + * any possible earlier value associated with the same key. + * @param key the key to associate the value with + * @param value the value to associate with the key + */ + protected abstract void setAttribute(String key, V value); + + /** + * Hook method that needs to be implemented by concrete subclasses. Removes a key and its associated value from the + * map. + * @param key the key to remove + */ + protected abstract void removeAttribute(String key); + + /** + * Hook method that needs to be implemented by concrete subclasses. Returns an enumeration listing all keys known to + * the map. + * @return the key enumeration + */ + protected abstract Iterator getAttributeNames(); + + // internal helper classes + + private abstract class AbstractSet extends java.util.AbstractSet { + public boolean isEmpty() { + return StringKeyedMapAdapter.this.isEmpty(); + } + + public int size() { + return StringKeyedMapAdapter.this.size(); + } + + public void clear() { + StringKeyedMapAdapter.this.clear(); + } + } + + private class KeySet extends AbstractSet { + public Iterator iterator() { + return new KeyIterator(); + } + + public boolean contains(Object o) { + return StringKeyedMapAdapter.this.containsKey(o); + } + + public boolean remove(Object o) { + return StringKeyedMapAdapter.this.remove(o) != null; + } + } + + private abstract class AbstractKeyIterator { + private final Iterator it = getAttributeNames(); + + private String currentKey; + + public void remove() { + if (currentKey == null) { + throw new NoSuchElementException("You must call next() at least once"); + } + StringKeyedMapAdapter.this.remove(currentKey); + } + + public boolean hasNext() { + return it.hasNext(); + } + + protected String nextKey() { + return currentKey = it.next(); + } + } + + private class KeyIterator extends AbstractKeyIterator implements Iterator { + public String next() { + return nextKey(); + } + } + + private class Values extends AbstractSet { + public Iterator iterator() { + return new ValuesIterator(); + } + + public boolean contains(Object o) { + return StringKeyedMapAdapter.this.containsValue(o); + } + + public boolean remove(Object o) { + if (o == null) { + return false; + } + for (Iterator it = iterator(); it.hasNext();) { + if (o.equals(it.next())) { + it.remove(); + return true; + } + } + return false; + } + } + + private class ValuesIterator extends AbstractKeyIterator implements Iterator { + public V next() { + return StringKeyedMapAdapter.this.get(nextKey()); + } + } + + private class EntrySet extends AbstractSet> { + public Iterator> iterator() { + return new EntryIterator(); + } + + public boolean contains(Object o) { + Entry entry = getAsEntry(o); + if (entry == null || entry.getKey() == null || entry.getValue() == null) { + return false; + } + V valueFromThisMap = StringKeyedMapAdapter.this.get(entry.getKey()); + return entry.getValue().equals(valueFromThisMap); + } + + public boolean remove(Object o) { + Entry entry = getAsEntry(o); + if (entry == null || entry.getKey() == null || entry.getValue() == null) { + return false; + } + V valueFromThisMap = StringKeyedMapAdapter.this.get(entry.getKey()); + if (!entry.getValue().equals(valueFromThisMap)) { + return false; + } + return StringKeyedMapAdapter.this.remove(entry.getKey()) != null; + } + + @SuppressWarnings("unchecked") + private Entry getAsEntry(Object o) { + if (o instanceof Entry) { + return (Entry) o; + } + return null; + } + } + + private class EntryIterator extends AbstractKeyIterator implements Iterator> { + public Entry next() { + return new EntrySetEntry(nextKey()); + } + } + + private class EntrySetEntry implements Entry { + private final String currentKey; + + public EntrySetEntry(String currentKey) { + this.currentKey = currentKey; + } + + public String getKey() { + return currentKey; + } + + public V getValue() { + return StringKeyedMapAdapter.this.get(currentKey); + } + + public V setValue(V value) { + return StringKeyedMapAdapter.this.put(currentKey, value); + } + } } diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/service/NoOpConverter.java b/spring-binding/src/main/java/org/springframework/binding/convert/service/NoOpConverter.java index f291e430..23c38f6d 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/service/NoOpConverter.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/service/NoOpConverter.java @@ -1,58 +1,58 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.binding.convert.service; - -import org.springframework.binding.convert.converters.Converter; - -/** - * Package private converter that is a "no op". - * - * @author Keith Donald - */ -class NoOpConverter implements Converter { - - private Class sourceClass; - - private Class targetClass; - - /** - * Create a "no op" converter from given source to given target class. - */ - public NoOpConverter(Class sourceClass, Class targetClass) { - this.sourceClass = sourceClass; - this.targetClass = targetClass; - } - - public Class getSourceClass() { - return sourceClass; - } - - public Class getTargetClass() { - return targetClass; - } - - public Object convertSourceToTargetClass(Object source, Class targetClass) { - return source; - } - - public boolean isTwoWay() { - return true; - } - - public Object convertTargetToSourceClass(Object target, Class sourceClass) { - return target; - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.binding.convert.service; + +import org.springframework.binding.convert.converters.Converter; + +/** + * Package private converter that is a "no op". + * + * @author Keith Donald + */ +class NoOpConverter implements Converter { + + private Class sourceClass; + + private Class targetClass; + + /** + * Create a "no op" converter from given source to given target class. + */ + public NoOpConverter(Class sourceClass, Class targetClass) { + this.sourceClass = sourceClass; + this.targetClass = targetClass; + } + + public Class getSourceClass() { + return sourceClass; + } + + public Class getTargetClass() { + return targetClass; + } + + public Object convertSourceToTargetClass(Object source, Class targetClass) { + return source; + } + + public boolean isTwoWay() { + return true; + } + + public Object convertTargetToSourceClass(Object target, Class sourceClass) { + return target; + } +} diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/support/CollectionAddingExpression.java b/spring-binding/src/main/java/org/springframework/binding/expression/support/CollectionAddingExpression.java index 02d08572..ec0d9408 100644 --- a/spring-binding/src/main/java/org/springframework/binding/expression/support/CollectionAddingExpression.java +++ b/spring-binding/src/main/java/org/springframework/binding/expression/support/CollectionAddingExpression.java @@ -1,76 +1,76 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.binding.expression.support; - -import java.util.Collection; - -import org.springframework.binding.expression.EvaluationException; -import org.springframework.binding.expression.Expression; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; - -/** - * A settable expression that adds non-null values to a collection. - * - * @author Keith Donald - */ -public class CollectionAddingExpression implements Expression { - - /** - * The expression that resolves a mutable collection reference. - */ - private Expression collectionExpression; - - /** - * Creates a collection adding property expression. - * @param collectionExpression the collection expression - */ - public CollectionAddingExpression(Expression collectionExpression) { - this.collectionExpression = collectionExpression; - } - - public Object getValue(Object context) throws EvaluationException { - return collectionExpression.getValue(context); - } - - @SuppressWarnings("unchecked") - public void setValue(Object context, Object value) throws EvaluationException { - Object result = getValue(context); - if (result == null) { - throw new EvaluationException(context.getClass(), collectionExpression.getExpressionString(), - "Unable to access collection value for expression '" + collectionExpression.getExpressionString() - + "'", new IllegalStateException( - "The collection expression evaluated to a [null] reference")); - } - Assert.isInstanceOf(Collection.class, result, "Not a collection: "); - if (value != null) { - // add the value to the collection - ((Collection) result).add(value); - } - } - - public Class getValueType(Object context) { - return Object.class; - } - - public String getExpressionString() { - return collectionExpression.getExpressionString(); - } - - public String toString() { - return new ToStringCreator(this).append("collectionExpression", collectionExpression).toString(); - } +/* + * Copyright 2004-2012 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 + * + * https://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.binding.expression.support; + +import java.util.Collection; + +import org.springframework.binding.expression.EvaluationException; +import org.springframework.binding.expression.Expression; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; + +/** + * A settable expression that adds non-null values to a collection. + * + * @author Keith Donald + */ +public class CollectionAddingExpression implements Expression { + + /** + * The expression that resolves a mutable collection reference. + */ + private Expression collectionExpression; + + /** + * Creates a collection adding property expression. + * @param collectionExpression the collection expression + */ + public CollectionAddingExpression(Expression collectionExpression) { + this.collectionExpression = collectionExpression; + } + + public Object getValue(Object context) throws EvaluationException { + return collectionExpression.getValue(context); + } + + @SuppressWarnings("unchecked") + public void setValue(Object context, Object value) throws EvaluationException { + Object result = getValue(context); + if (result == null) { + throw new EvaluationException(context.getClass(), collectionExpression.getExpressionString(), + "Unable to access collection value for expression '" + collectionExpression.getExpressionString() + + "'", new IllegalStateException( + "The collection expression evaluated to a [null] reference")); + } + Assert.isInstanceOf(Collection.class, result, "Not a collection: "); + if (value != null) { + // add the value to the collection + ((Collection) result).add(value); + } + } + + public Class getValueType(Object context) { + return Object.class; + } + + public String getExpressionString() { + return collectionExpression.getExpressionString(); + } + + public String toString() { + return new ToStringCreator(this).append("collectionExpression", collectionExpression).toString(); + } } diff --git a/spring-binding/src/test/java/org/springframework/binding/convert/service/StaticConversionExecutorImplTests.java b/spring-binding/src/test/java/org/springframework/binding/convert/service/StaticConversionExecutorImplTests.java index 0d0bef7c..e32dee1d 100644 --- a/spring-binding/src/test/java/org/springframework/binding/convert/service/StaticConversionExecutorImplTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/convert/service/StaticConversionExecutorImplTests.java @@ -1,70 +1,70 @@ -/* - * 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 - * - * https://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.binding.convert.service; - -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.Date; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.binding.convert.ConversionExecutionException; -import org.springframework.binding.convert.converters.StringToDate; - -public class StaticConversionExecutorImplTests { - - private StaticConversionExecutor conversionExecutor; - +/* + * 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 + * + * https://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.binding.convert.service; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Date; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.binding.convert.ConversionExecutionException; +import org.springframework.binding.convert.converters.StringToDate; + +public class StaticConversionExecutorImplTests { + + private StaticConversionExecutor conversionExecutor; + @BeforeEach - public void setUp() { - StringToDate stringToDate = new StringToDate(); - conversionExecutor = new StaticConversionExecutor(String.class, Date.class, stringToDate); - } - + public void setUp() { + StringToDate stringToDate = new StringToDate(); + conversionExecutor = new StaticConversionExecutor(String.class, Date.class, stringToDate); + } + @Test - public void testTypeConversion() { - assertTrue(conversionExecutor.execute("2008-10-10").getClass().equals(Date.class)); - } - + public void testTypeConversion() { + assertTrue(conversionExecutor.execute("2008-10-10").getClass().equals(Date.class)); + } + @Test - public void testAssignmentCompatibleTypeConversion() { - java.sql.Date date = new java.sql.Date(123L); - try { - assertSame(date, conversionExecutor.execute(date)); - fail("Should have failed"); - } catch (ConversionExecutionException e) { - - } - } - + public void testAssignmentCompatibleTypeConversion() { + java.sql.Date date = new java.sql.Date(123L); + try { + assertSame(date, conversionExecutor.execute(date)); + fail("Should have failed"); + } catch (ConversionExecutionException e) { + + } + } + @Test - public void testConvertNull() { - assertNull(conversionExecutor.execute(null)); - } - + public void testConvertNull() { + assertNull(conversionExecutor.execute(null)); + } + @Test - public void testIllegalType() { - try { - conversionExecutor.execute(new StringBuilder()); - fail(); - } catch (ConversionExecutionException e) { - // expected - } - } -} + public void testIllegalType() { + try { + conversionExecutor.execute(new StringBuilder()); + fail(); + } catch (ConversionExecutionException e) { + // expected + } + } +} diff --git a/spring-binding/src/test/java/org/springframework/binding/method/MethodInvocationExceptionTests.java b/spring-binding/src/test/java/org/springframework/binding/method/MethodInvocationExceptionTests.java index 26da71a1..b56fbd6a 100644 --- a/spring-binding/src/test/java/org/springframework/binding/method/MethodInvocationExceptionTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/method/MethodInvocationExceptionTests.java @@ -1,60 +1,60 @@ -/* - * 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 - * - * https://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.binding.method; - -import static org.junit.jupiter.api.Assertions.assertSame; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; - -import org.junit.jupiter.api.Test; - -/** - * Test case for {@link MethodInvocationException}. - * - * @author Erwin Vervaet - */ -public class MethodInvocationExceptionTests { - +/* + * 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 + * + * https://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.binding.method; + +import static org.junit.jupiter.api.Assertions.assertSame; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import org.junit.jupiter.api.Test; + +/** + * Test case for {@link MethodInvocationException}. + * + * @author Erwin Vervaet + */ +public class MethodInvocationExceptionTests { + @Test - public void testGetTargetException() { - // runtime exception - IllegalArgumentException iae = new IllegalArgumentException("test"); - MethodInvocationException ex = testException(iae); - assertSame(iae, ex.getTargetException()); - - // exception - IOException ioe = new IOException("test"); - ex = testException(ioe); - assertSame(ioe, ex.getTargetException()); - - // nested - InvocationTargetException ite = new InvocationTargetException(ioe); - ex = testException(ite); - assertSame(ioe, ex.getTargetException()); - - // deep nesting - ite = new InvocationTargetException(new InvocationTargetException(ioe)); - ex = testException(ite); - assertSame(ioe, ex.getTargetException()); - } - - // internal helpers - - private MethodInvocationException testException(Throwable cause) { - return new MethodInvocationException(new MethodSignature("test"), null, cause); - } -} + public void testGetTargetException() { + // runtime exception + IllegalArgumentException iae = new IllegalArgumentException("test"); + MethodInvocationException ex = testException(iae); + assertSame(iae, ex.getTargetException()); + + // exception + IOException ioe = new IOException("test"); + ex = testException(ioe); + assertSame(ioe, ex.getTargetException()); + + // nested + InvocationTargetException ite = new InvocationTargetException(ioe); + ex = testException(ite); + assertSame(ioe, ex.getTargetException()); + + // deep nesting + ite = new InvocationTargetException(new InvocationTargetException(ioe)); + ex = testException(ite); + assertSame(ioe, ex.getTargetException()); + } + + // internal helpers + + private MethodInvocationException testException(Throwable cause) { + return new MethodInvocationException(new MethodSignature("test"), null, cause); + } +} diff --git a/spring-binding/src/test/java/org/springframework/binding/method/MethodInvokerTests.java b/spring-binding/src/test/java/org/springframework/binding/method/MethodInvokerTests.java index 3ab7ce7d..a3331508 100644 --- a/spring-binding/src/test/java/org/springframework/binding/method/MethodInvokerTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/method/MethodInvokerTests.java @@ -1,98 +1,98 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.binding.method; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.binding.expression.support.StaticExpression; - -/** - * Unit tests for {@link org.springframework.binding.method.MethodInvoker}. - * - * @author Erwin Vervaet - * @author Jeremy Grelle - */ -public class MethodInvokerTests { - - private MethodInvoker methodInvoker; - +/* + * Copyright 2004-2012 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 + * + * https://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.binding.method; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.binding.expression.support.StaticExpression; + +/** + * Unit tests for {@link org.springframework.binding.method.MethodInvoker}. + * + * @author Erwin Vervaet + * @author Jeremy Grelle + */ +public class MethodInvokerTests { + + private MethodInvoker methodInvoker; + @BeforeEach - public void setUp() { - this.methodInvoker = new MethodInvoker(); - } - + public void setUp() { + this.methodInvoker = new MethodInvoker(); + } + @Test - public void testInvocationTargetException() { - try { - methodInvoker.invoke(new MethodSignature("test"), new TestObject(), null); - fail(); - } catch (MethodInvocationException e) { - assertTrue(e.getTargetException() instanceof IllegalArgumentException); - assertEquals("just testing", e.getTargetException().getMessage()); - } - } - + public void testInvocationTargetException() { + try { + methodInvoker.invoke(new MethodSignature("test"), new TestObject(), null); + fail(); + } catch (MethodInvocationException e) { + assertTrue(e.getTargetException() instanceof IllegalArgumentException); + assertEquals("just testing", e.getTargetException().getMessage()); + } + } + @Test - public void testInvalidMethod() { - try { - methodInvoker.invoke(new MethodSignature("bogus"), new TestObject(), null); - fail(); - } catch (MethodInvocationException e) { - assertTrue(e.getTargetException() instanceof InvalidMethodKeyException); - } - } - + public void testInvalidMethod() { + try { + methodInvoker.invoke(new MethodSignature("bogus"), new TestObject(), null); + fail(); + } catch (MethodInvocationException e) { + assertTrue(e.getTargetException() instanceof InvalidMethodKeyException); + } + } + @Test - public void testBeanArg() { - Parameters parameters = new Parameters(); - Bean bean = new Bean(); - parameters.add(new Parameter(Bean.class, new StaticExpression(bean))); - MethodSignature method = new MethodSignature("testBeanArg", parameters); - assertSame(bean, methodInvoker.invoke(method, new TestObject(), null)); - } - + public void testBeanArg() { + Parameters parameters = new Parameters(); + Bean bean = new Bean(); + parameters.add(new Parameter(Bean.class, new StaticExpression(bean))); + MethodSignature method = new MethodSignature("testBeanArg", parameters); + assertSame(bean, methodInvoker.invoke(method, new TestObject(), null)); + } + @Test - public void testPrimitiveArg() { - Parameters parameters = new Parameters(); - parameters.add(new Parameter(Boolean.class, new StaticExpression(true))); - MethodSignature method = new MethodSignature("testPrimitiveArg", parameters); - assertEquals(Boolean.TRUE, methodInvoker.invoke(method, new TestObject(), null)); - } - - static class TestObject { - - public void test() { - throw new IllegalArgumentException("just testing"); - } - - public Object testBeanArg(Bean bean) { - return bean; - } - - public boolean testPrimitiveArg(boolean primitive) { - return primitive; - } - } - - static class Bean { - String value; - } -} + public void testPrimitiveArg() { + Parameters parameters = new Parameters(); + parameters.add(new Parameter(Boolean.class, new StaticExpression(true))); + MethodSignature method = new MethodSignature("testPrimitiveArg", parameters); + assertEquals(Boolean.TRUE, methodInvoker.invoke(method, new TestObject(), null)); + } + + static class TestObject { + + public void test() { + throw new IllegalArgumentException("just testing"); + } + + public Object testBeanArg(Bean bean) { + return bean; + } + + public boolean testPrimitiveArg(boolean primitive) { + return primitive; + } + } + + static class Bean { + String value; + } +} diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFManagedBean.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFManagedBean.java index c8410608..bf2e52dc 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFManagedBean.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFManagedBean.java @@ -1,35 +1,35 @@ -package org.springframework.faces.webflow; - -import java.util.ArrayList; -import java.util.List; - -public class JSFManagedBean { - - String prop1; - JSFModel model; - List values = new ArrayList<>(); - - public JSFModel getModel() { - return this.model; - } - - public void setModel(JSFModel model) { - this.model = model; - } - - public String getProp1() { - return this.prop1; - } - - public void setProp1(String prop1) { - this.prop1 = prop1; - } - - public void addValue(String value) { - this.values.add(value); - } - - public List getValues() { - return this.values; - } -} +package org.springframework.faces.webflow; + +import java.util.ArrayList; +import java.util.List; + +public class JSFManagedBean { + + String prop1; + JSFModel model; + List values = new ArrayList<>(); + + public JSFModel getModel() { + return this.model; + } + + public void setModel(JSFModel model) { + this.model = model; + } + + public String getProp1() { + return this.prop1; + } + + public void setProp1(String prop1) { + this.prop1 = prop1; + } + + public void addValue(String value) { + this.values.add(value); + } + + public List getValues() { + return this.values; + } +} diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java index d61bfd62..484ee21f 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java @@ -1,240 +1,240 @@ -package org.springframework.faces.webflow; - -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; - -import javax.faces.FactoryFinder; -import javax.faces.application.Application; -import javax.faces.application.ApplicationFactory; -import javax.faces.component.UIViewRoot; -import javax.faces.context.FacesContext; -import javax.faces.context.FacesContextFactory; -import javax.faces.lifecycle.LifecycleFactory; -import javax.faces.render.RenderKitFactory; - -import org.apache.myfaces.test.base.AbstractJsfTestCase; -import org.apache.myfaces.test.mock.MockApplicationFactory; -import org.apache.myfaces.test.mock.MockExternalContext; -import org.apache.myfaces.test.mock.MockHttpServletRequest; -import org.apache.myfaces.test.mock.MockHttpServletResponse; -import org.apache.myfaces.test.mock.MockHttpSession; -import org.apache.myfaces.test.mock.MockPartialViewContextFactory; -import org.apache.myfaces.test.mock.MockPrintWriter; -import org.apache.myfaces.test.mock.MockRenderKit; -import org.apache.myfaces.test.mock.MockRenderKitFactory; -import org.apache.myfaces.test.mock.MockResponseWriter; -import org.apache.myfaces.test.mock.MockServletConfig; -import org.apache.myfaces.test.mock.MockServletContext; -import org.apache.myfaces.test.mock.lifecycle.MockLifecycle; -import org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory; -import org.apache.myfaces.test.mock.visit.MockVisitContextFactory; - -/** - * Helper for using the mock JSF environment provided by shale-test inside unit tests that do not extend - * {@link AbstractJsfTestCase} - * - * @author Jeremy Grelle - * @author Phillip Webb - */ -public class JSFMockHelper { - - private final JSFMock mock = new JSFMock(); - - public Application application() { - return this.mock.application(); - } - - public MockServletConfig config() { - return this.mock.config(); - } - - public String contentAsString() throws IOException { - return this.mock.contentAsString(); - } - - public MockExternalContext externalContext() { - return this.mock.externalContext(); - } - - public FacesContext facesContext() { - return this.mock.facesContext(); - } - - public FacesContextFactory facesContextFactory() { - return this.mock.facesContextFactory(); - } - - public MockLifecycle lifecycle() { - return this.mock.lifecycle(); - } - - public MockLifecycleFactory lifecycleFactory() { - return this.mock.lifecycleFactory(); - } - - public MockRenderKit renderKit() { - return this.mock.renderKit(); - } - - public MockHttpServletRequest request() { - return this.mock.request(); - } - - public MockHttpServletResponse response() { - return this.mock.response(); - } - - public MockServletContext servletContext() { - return this.mock.servletContext(); - } - - public MockHttpSession session() { - return this.mock.session(); - } - - public void setUp() throws Exception { - this.mock.setUp(); - } - - public void tearDown() throws Exception { - this.mock.tearDown(); - } - - private static class JSFMock extends AbstractJsfTestCase { - - private ClassLoader threadContextClassLoader; - - public JSFMock() { - super("JSFMock"); - } - - FacesContext facesContext; - FacesContextFactory facesContextFactory; - - public void setUp() throws Exception { - - // Ensure no pre-existing FacesContext .. - if (FacesContext.getCurrentInstance() != null) { - FacesContext.getCurrentInstance().release(); - } - - // Set up a new thread context class loader - this.threadContextClassLoader = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader( - new URLClassLoader(new URL[0], this.getClass().getClassLoader())); - - // Set up Servlet API Objects - this.servletContext = new MockServletContext(); - this.config = new MockServletConfig(this.servletContext); - this.session = new MockHttpSession(); - this.session.setServletContext(this.servletContext); - this.request = new MockHttpServletRequest(this.session); - this.request.setServletContext(this.servletContext); - this.response = new MockHttpServletResponse(); - - // Set up JSF API Objects - FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, MockApplicationFactory.class.getName()); - FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY, MockBaseFacesContextFactory.class.getName()); - FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY, MockLifecycleFactory.class.getName()); - FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY, MockRenderKitFactory.class.getName()); - FactoryFinder.setFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY, - MockPartialViewContextFactory.class.getName()); - FactoryFinder.setFactory(FactoryFinder.VISIT_CONTEXT_FACTORY, MockVisitContextFactory.class.getName()); - this.lifecycleFactory = (MockLifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); - this.lifecycle = (MockLifecycle) this.lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE); - this.facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); - this.facesContext = this.facesContextFactory.getFacesContext(this.servletContext, this.request, this.response, this.lifecycle); - this.externalContext = (MockExternalContext) this.facesContext.getExternalContext(); - this.facesContext.setResponseWriter(new MockResponseWriter(this.response.getWriter())); - - UIViewRoot root = new UIViewRoot(); - root.setViewId("/viewId"); - root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT); - this.facesContext.setViewRoot(root); - ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder - .getFactory(FactoryFinder.APPLICATION_FACTORY); - this.application = (org.apache.myfaces.test.mock.MockApplication) applicationFactory.getApplication(); - RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder - .getFactory(FactoryFinder.RENDER_KIT_FACTORY); - this.renderKit = new MockRenderKit(); - renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT, this.renderKit); - } - - public void tearDown() throws Exception { - this.application = null; - this.config = null; - this.externalContext = null; - if (this.facesContext != null) { - this.facesContext.release(); - } - this.facesContext = null; - this.lifecycle = null; - this.lifecycleFactory = null; - this.renderKit = null; - this.request = null; - this.response = null; - this.servletContext = null; - this.session = null; - FactoryFinder.releaseFactories(); - - Thread.currentThread().setContextClassLoader(this.threadContextClassLoader); - this.threadContextClassLoader = null; - } - - public org.apache.myfaces.test.mock.MockApplication application() { - return this.application; - } - - public MockServletConfig config() { - return this.config; - } - - public String contentAsString() throws IOException { - MockPrintWriter writer = (MockPrintWriter) this.response.getWriter(); - return new String(writer.content()); - } - - public MockExternalContext externalContext() { - return this.externalContext; - } - - public FacesContext facesContext() { - return this.facesContext; - } - - public FacesContextFactory facesContextFactory() { - return this.facesContextFactory; - } - - public MockLifecycle lifecycle() { - return this.lifecycle; - } - - public MockLifecycleFactory lifecycleFactory() { - return this.lifecycleFactory; - } - - public MockRenderKit renderKit() { - return this.renderKit; - } - - public MockHttpServletRequest request() { - return this.request; - } - - public MockHttpServletResponse response() { - return this.response; - } - - public MockServletContext servletContext() { - return this.servletContext; - } - - public MockHttpSession session() { - return this.session; - } - - } - -} +package org.springframework.faces.webflow; + +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; + +import javax.faces.FactoryFinder; +import javax.faces.application.Application; +import javax.faces.application.ApplicationFactory; +import javax.faces.component.UIViewRoot; +import javax.faces.context.FacesContext; +import javax.faces.context.FacesContextFactory; +import javax.faces.lifecycle.LifecycleFactory; +import javax.faces.render.RenderKitFactory; + +import org.apache.myfaces.test.base.AbstractJsfTestCase; +import org.apache.myfaces.test.mock.MockApplicationFactory; +import org.apache.myfaces.test.mock.MockExternalContext; +import org.apache.myfaces.test.mock.MockHttpServletRequest; +import org.apache.myfaces.test.mock.MockHttpServletResponse; +import org.apache.myfaces.test.mock.MockHttpSession; +import org.apache.myfaces.test.mock.MockPartialViewContextFactory; +import org.apache.myfaces.test.mock.MockPrintWriter; +import org.apache.myfaces.test.mock.MockRenderKit; +import org.apache.myfaces.test.mock.MockRenderKitFactory; +import org.apache.myfaces.test.mock.MockResponseWriter; +import org.apache.myfaces.test.mock.MockServletConfig; +import org.apache.myfaces.test.mock.MockServletContext; +import org.apache.myfaces.test.mock.lifecycle.MockLifecycle; +import org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory; +import org.apache.myfaces.test.mock.visit.MockVisitContextFactory; + +/** + * Helper for using the mock JSF environment provided by shale-test inside unit tests that do not extend + * {@link AbstractJsfTestCase} + * + * @author Jeremy Grelle + * @author Phillip Webb + */ +public class JSFMockHelper { + + private final JSFMock mock = new JSFMock(); + + public Application application() { + return this.mock.application(); + } + + public MockServletConfig config() { + return this.mock.config(); + } + + public String contentAsString() throws IOException { + return this.mock.contentAsString(); + } + + public MockExternalContext externalContext() { + return this.mock.externalContext(); + } + + public FacesContext facesContext() { + return this.mock.facesContext(); + } + + public FacesContextFactory facesContextFactory() { + return this.mock.facesContextFactory(); + } + + public MockLifecycle lifecycle() { + return this.mock.lifecycle(); + } + + public MockLifecycleFactory lifecycleFactory() { + return this.mock.lifecycleFactory(); + } + + public MockRenderKit renderKit() { + return this.mock.renderKit(); + } + + public MockHttpServletRequest request() { + return this.mock.request(); + } + + public MockHttpServletResponse response() { + return this.mock.response(); + } + + public MockServletContext servletContext() { + return this.mock.servletContext(); + } + + public MockHttpSession session() { + return this.mock.session(); + } + + public void setUp() throws Exception { + this.mock.setUp(); + } + + public void tearDown() throws Exception { + this.mock.tearDown(); + } + + private static class JSFMock extends AbstractJsfTestCase { + + private ClassLoader threadContextClassLoader; + + public JSFMock() { + super("JSFMock"); + } + + FacesContext facesContext; + FacesContextFactory facesContextFactory; + + public void setUp() throws Exception { + + // Ensure no pre-existing FacesContext .. + if (FacesContext.getCurrentInstance() != null) { + FacesContext.getCurrentInstance().release(); + } + + // Set up a new thread context class loader + this.threadContextClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader( + new URLClassLoader(new URL[0], this.getClass().getClassLoader())); + + // Set up Servlet API Objects + this.servletContext = new MockServletContext(); + this.config = new MockServletConfig(this.servletContext); + this.session = new MockHttpSession(); + this.session.setServletContext(this.servletContext); + this.request = new MockHttpServletRequest(this.session); + this.request.setServletContext(this.servletContext); + this.response = new MockHttpServletResponse(); + + // Set up JSF API Objects + FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, MockApplicationFactory.class.getName()); + FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY, MockBaseFacesContextFactory.class.getName()); + FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY, MockLifecycleFactory.class.getName()); + FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY, MockRenderKitFactory.class.getName()); + FactoryFinder.setFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY, + MockPartialViewContextFactory.class.getName()); + FactoryFinder.setFactory(FactoryFinder.VISIT_CONTEXT_FACTORY, MockVisitContextFactory.class.getName()); + this.lifecycleFactory = (MockLifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); + this.lifecycle = (MockLifecycle) this.lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE); + this.facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); + this.facesContext = this.facesContextFactory.getFacesContext(this.servletContext, this.request, this.response, this.lifecycle); + this.externalContext = (MockExternalContext) this.facesContext.getExternalContext(); + this.facesContext.setResponseWriter(new MockResponseWriter(this.response.getWriter())); + + UIViewRoot root = new UIViewRoot(); + root.setViewId("/viewId"); + root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT); + this.facesContext.setViewRoot(root); + ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder + .getFactory(FactoryFinder.APPLICATION_FACTORY); + this.application = (org.apache.myfaces.test.mock.MockApplication) applicationFactory.getApplication(); + RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder + .getFactory(FactoryFinder.RENDER_KIT_FACTORY); + this.renderKit = new MockRenderKit(); + renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT, this.renderKit); + } + + public void tearDown() throws Exception { + this.application = null; + this.config = null; + this.externalContext = null; + if (this.facesContext != null) { + this.facesContext.release(); + } + this.facesContext = null; + this.lifecycle = null; + this.lifecycleFactory = null; + this.renderKit = null; + this.request = null; + this.response = null; + this.servletContext = null; + this.session = null; + FactoryFinder.releaseFactories(); + + Thread.currentThread().setContextClassLoader(this.threadContextClassLoader); + this.threadContextClassLoader = null; + } + + public org.apache.myfaces.test.mock.MockApplication application() { + return this.application; + } + + public MockServletConfig config() { + return this.config; + } + + public String contentAsString() throws IOException { + MockPrintWriter writer = (MockPrintWriter) this.response.getWriter(); + return new String(writer.content()); + } + + public MockExternalContext externalContext() { + return this.externalContext; + } + + public FacesContext facesContext() { + return this.facesContext; + } + + public FacesContextFactory facesContextFactory() { + return this.facesContextFactory; + } + + public MockLifecycle lifecycle() { + return this.lifecycle; + } + + public MockLifecycleFactory lifecycleFactory() { + return this.lifecycleFactory; + } + + public MockRenderKit renderKit() { + return this.renderKit; + } + + public MockHttpServletRequest request() { + return this.request; + } + + public MockHttpServletResponse response() { + return this.response; + } + + public MockServletContext servletContext() { + return this.servletContext; + } + + public MockHttpSession session() { + return this.session; + } + + } + +} diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFModel.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFModel.java index 0b136ee1..d1ca369a 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFModel.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFModel.java @@ -1,13 +1,13 @@ -package org.springframework.faces.webflow; - -public class JSFModel { - String value; - - public String getValue() { - return this.value; - } - - public void setValue(String value) { - this.value = value; - } -} +package org.springframework.faces.webflow; + +public class JSFModel { + String value; + + public String getValue() { + return this.value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/MockService.java b/spring-faces/src/test/java/org/springframework/faces/webflow/MockService.java index 8a2183ce..4eb54962 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/MockService.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/MockService.java @@ -1,6 +1,6 @@ -package org.springframework.faces.webflow; - -public interface MockService { - - void doSomething(String arg); -} +package org.springframework.faces.webflow; + +public interface MockService { + + void doSomething(String arg); +} diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/forms.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/forms.css index 3b3e47ef..26f5e4cb 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/forms.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/forms.css @@ -1,134 +1,134 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* FORM ELEMENTS */ - form { - margin:0; - padding:0; - } - form div, - form p { - margin: 0 0 1em 0; - padding: 0; - - font-size: 1em; - } - label { - font-weight: bold; - } - fieldset { - padding: 5px 10px; - margin: 0 0 1.5em 0; - - border: 1px solid #eee; - } - fieldset legend { - margin: 0 0 0 0px; - padding: 0; - - font-size: 1.1em; - font-weight: bold; - - color: #666; - background-color: white; - } - * html fieldset legend { - margin: 0 0 10px -10px; - } - fieldset ul { - margin: 0 0 1.5em 0; - padding: 0; - - list-style: none; - } - fieldset ul li { - margin: 0 0 0.5em 0; - padding: 0; - - list-style: none; - } - input, select, textarea { - margin: 0; - padding: 2px; - - font-size: 1em; - font-family: arial, helvetica, verdana, sans-serif; - } - - input, select { - vertical-align: middle; - } - textarea { - width: 200px; - height: 8em; - } - - input.check { - width: auto; - height: auto; - - margin: 0; - - border: none; - } - input.radio { - width: auto; - - height: auto; - margin: 0; - - border: none; - } - input.file { - width: 250px; - height: auto; - } - input.readonly { - background-color: transparent; - border: none; - } - input.button { - width: 10em; - - background-color: #ddd; - border: 1px solid black; - } - input.image { - width: auto; - height: auto; - - border: none; - } - - form div.submit { - margin: 1em 0; - } - form div.submit input { - width: 15em; - height: 2em; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* FORM ELEMENTS */ + form { + margin:0; + padding:0; + } + form div, + form p { + margin: 0 0 1em 0; + padding: 0; + + font-size: 1em; + } + label { + font-weight: bold; + } + fieldset { + padding: 5px 10px; + margin: 0 0 1.5em 0; + + border: 1px solid #eee; + } + fieldset legend { + margin: 0 0 0 0px; + padding: 0; + + font-size: 1.1em; + font-weight: bold; + + color: #666; + background-color: white; + } + * html fieldset legend { + margin: 0 0 10px -10px; + } + fieldset ul { + margin: 0 0 1.5em 0; + padding: 0; + + list-style: none; + } + fieldset ul li { + margin: 0 0 0.5em 0; + padding: 0; + + list-style: none; + } + input, select, textarea { + margin: 0; + padding: 2px; + + font-size: 1em; + font-family: arial, helvetica, verdana, sans-serif; + } + + input, select { + vertical-align: middle; + } + textarea { + width: 200px; + height: 8em; + } + + input.check { + width: auto; + height: auto; + + margin: 0; + + border: none; + } + input.radio { + width: auto; + + height: auto; + margin: 0; + + border: none; + } + input.file { + width: 250px; + height: auto; + } + input.readonly { + background-color: transparent; + border: none; + } + input.button { + width: 10em; + + background-color: #ddd; + border: 1px solid black; + } + input.image { + width: auto; + height: auto; + + border: none; + } + + form div.submit { + margin: 1em 0; + } + form div.submit input { + width: 15em; + height: 2em; + } /* END FORM ELEMENTS */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-1col.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-1col.css index 7f3de7b4..695aa689 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-1col.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-1col.css @@ -1,52 +1,52 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -@import url("nav-horizontal.css"); - -/* NAV BAR AT THE TOP AND ONE COLUMN OF CONTENT */ - div#content { - position: relative; - width: 701px; - - margin: 0 auto 20px auto; - padding: 0; - - text-align: left; - } - div#main { - width: 100%; - } - div#local { - display: none; - } - div#sub { - display: none; - } - div#nav { - display: none; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +@import url("nav-horizontal.css"); + +/* NAV BAR AT THE TOP AND ONE COLUMN OF CONTENT */ + div#content { + position: relative; + width: 701px; + + margin: 0 auto 20px auto; + padding: 0; + + text-align: left; + } + div#main { + width: 100%; + } + div#local { + display: none; + } + div#sub { + display: none; + } + div#nav { + display: none; + } /* END CONTENT */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navleft-1col.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navleft-1col.css index 9840d71c..48b9ebc6 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navleft-1col.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navleft-1col.css @@ -1,56 +1,56 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -@import url("nav-vertical.css"); - -/* NAV BAR ON THE LEFT AND ONE COLUMN OF CONTENT */ - div#content { - position: relative; - width: 780px; - - margin: 0 auto 20px auto; - padding: 0; - - text-align: left; - } - div#main { - float: right; - width: 560px; - display: inline; - } - div#local { - display: none; - } - div#sub { - display: none; - } - div#nav { - float: left; - width: 200px; - display: inline; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +@import url("nav-vertical.css"); + +/* NAV BAR ON THE LEFT AND ONE COLUMN OF CONTENT */ + div#content { + position: relative; + width: 780px; + + margin: 0 auto 20px auto; + padding: 0; + + text-align: left; + } + div#main { + float: right; + width: 560px; + display: inline; + } + div#local { + display: none; + } + div#sub { + display: none; + } + div#nav { + float: left; + width: 200px; + display: inline; + } /* END CONTENT */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navleft-2col.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navleft-2col.css index a2fa6061..adbc1215 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navleft-2col.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navleft-2col.css @@ -1,64 +1,64 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -@import url("nav-vertical.css"); - -/* NAV BAR ON THE LEFT AND TWO COLUMNS OF CONTENT */ - div#content { - position: relative; - width: 780px; - - margin: 0 auto 20px auto; - padding: 0; - - text-align: left; - } - div#main { - float: right; - width: 340px; - display: inline; - - margin-right: 220px; - margin-left: -220px; - } - div#local { - display: none; - } - div#sub { - float: right; - width: 200px; - display: inline; - - margin-right: -340px; - margin-left: 200px; - } - div#nav { - float: left; - width: 200px; - display: inline; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +@import url("nav-vertical.css"); + +/* NAV BAR ON THE LEFT AND TWO COLUMNS OF CONTENT */ + div#content { + position: relative; + width: 780px; + + margin: 0 auto 20px auto; + padding: 0; + + text-align: left; + } + div#main { + float: right; + width: 340px; + display: inline; + + margin-right: 220px; + margin-left: -220px; + } + div#local { + display: none; + } + div#sub { + float: right; + width: 200px; + display: inline; + + margin-right: -340px; + margin-left: 200px; + } + div#nav { + float: left; + width: 200px; + display: inline; + } /* END CONTENT */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-1col.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-1col.css index 635494b7..e5b6ceea 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-1col.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-1col.css @@ -1,57 +1,57 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -@import url("nav-horizontal.css"); - -/* NAV BAR AT THE TOP AND ONE COLUMN OF CONTENT */ - div#content { - position: relative; - width: 701px; - - margin: 0 auto 20px auto; - padding: 0; - - text-align: left; - } - div#main { - width: 100%; - } - div#local { - width: 100%; - } - div#sub { - width: 100%; - } - div#nav { - position: absolute; - top: -15px; - left: 0; - width: 100%; - - text-align: left; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +@import url("nav-horizontal.css"); + +/* NAV BAR AT THE TOP AND ONE COLUMN OF CONTENT */ + div#content { + position: relative; + width: 701px; + + margin: 0 auto 20px auto; + padding: 0; + + text-align: left; + } + div#main { + width: 100%; + } + div#local { + width: 100%; + } + div#sub { + width: 100%; + } + div#nav { + position: absolute; + top: -15px; + left: 0; + width: 100%; + + text-align: left; + } /* END CONTENT */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-3col.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-3col.css index 599fa997..a2ceab4f 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-3col.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-3col.css @@ -1,68 +1,68 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -@import url("nav-horizontal.css"); - -/* NAV BAR AT THE TOP, LOCAL NAV ON THE LEFT AND TWO COLUMNS OF CONTENT */ - div#content { - position: relative; - width: 701px; - - margin: 0 auto 20px auto; - padding: 0; - - text-align: left; - } - div#main { - float: left; - width: 300px; - display: inline; - - margin-right: -200px; - margin-left: 200px; - } - div#sub { - float: right; - width: 180px; - display: inline; - } - div#local { - float: left; - width: 180px; - display: inline; - - margin-left: -300px; - } - div#nav { - position: absolute; - top: -15px; - left: 0; - width: 701px; - - text-align: left; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +@import url("nav-horizontal.css"); + +/* NAV BAR AT THE TOP, LOCAL NAV ON THE LEFT AND TWO COLUMNS OF CONTENT */ + div#content { + position: relative; + width: 701px; + + margin: 0 auto 20px auto; + padding: 0; + + text-align: left; + } + div#main { + float: left; + width: 300px; + display: inline; + + margin-right: -200px; + margin-left: 200px; + } + div#sub { + float: right; + width: 180px; + display: inline; + } + div#local { + float: left; + width: 180px; + display: inline; + + margin-left: -300px; + } + div#nav { + position: absolute; + top: -15px; + left: 0; + width: 701px; + + text-align: left; + } /* END CONTENT */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-localleft.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-localleft.css index 1cf0c61d..b9c0e6ef 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-localleft.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-localleft.css @@ -1,61 +1,61 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -@import url("nav-horizontal.css"); - -/* NAV BAR AT THE TOP, LOCAL NAVIGATION ON THE LEFT AND ONE COLUMN OF CONTENT */ - div#content { - position: relative; - width: 701px; - - margin: 0 auto 20px auto; - padding: 0; - - text-align: left; - } - div#main { - float: right; - width: 500px; - display: inline; - } - div#local { - float: left; - width: 200px; - display: inline; - } - div#sub { - display: none; - } - div#nav { - position: absolute; - top: -15px; - left: 0; - width: 100%; - - text-align: left; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +@import url("nav-horizontal.css"); + +/* NAV BAR AT THE TOP, LOCAL NAVIGATION ON THE LEFT AND ONE COLUMN OF CONTENT */ + div#content { + position: relative; + width: 701px; + + margin: 0 auto 20px auto; + padding: 0; + + text-align: left; + } + div#main { + float: right; + width: 500px; + display: inline; + } + div#local { + float: left; + width: 200px; + display: inline; + } + div#sub { + display: none; + } + div#nav { + position: absolute; + top: -15px; + left: 0; + width: 100%; + + text-align: left; + } /* END CONTENT */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-subright.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-subright.css index 47384ca1..72360c6e 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-subright.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout-navtop-subright.css @@ -1,61 +1,61 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -@import url("nav-horizontal.css"); - -/* NAV BAR AT THE TOP AND TWO COLUMNS OF CONTENT */ - div#content { - position: relative; - width: 701px; - - margin: 0 auto 20px auto; - padding: 0; - - text-align: left; - } - div#main { - float: left; - width: 480px; - display: inline; - } - div#sub { - float: right; - width: 200px; - display: inline; - } - div#local { - display: none; - } - div#nav { - position: absolute; - top: -15px; - left: 0; - width: 100%; - - text-align: left; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +@import url("nav-horizontal.css"); + +/* NAV BAR AT THE TOP AND TWO COLUMNS OF CONTENT */ + div#content { + position: relative; + width: 701px; + + margin: 0 auto 20px auto; + padding: 0; + + text-align: left; + } + div#main { + float: left; + width: 480px; + display: inline; + } + div#sub { + float: right; + width: 200px; + display: inline; + } + div#local { + display: none; + } + div#nav { + position: absolute; + top: -15px; + left: 0; + width: 100%; + + text-align: left; + } /* END CONTENT */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout.css index b6f3cfe0..7beb4f22 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/layout.css @@ -1,152 +1,152 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* SITE SPECIFIC LAYOUT */ - body { - margin: 0; - padding: 0; - - text-align: center; - - background: white; - } - div#page { - width: 780px; - - margin: 0 auto; - padding: 0; - - text-align: center; - - background: white; - } - - /* HEADER */ - div#header { - margin: 0 0 5em 0; - padding: 40px 20px; - - color: white; - background: black; - - text-align: left; - } - div#branding { - float: left; - width: 40%; - - margin: 0; - padding: 10px 0 10px 20px; - - text-align: left; - } - div#search { - float: right; - width: 49%; - - margin: 0; - padding: 16px 20px 0 0; - - text-align: right; - } - /* END HEADER */ - - - /* CONTENT */ - div#content { - - } - - /* MAIN */ - div#main { - - } - /* END MAIN */ - - /* SUB */ - div#sub { - - } - /* END SUB */ - - /* END CONTENT */ - - - /* FOOTER */ - div#footer { - color: white; - background-color: black; - } - div#footer p { - margin: 0; - padding: 15px; - - font-size: 0.8em; - } - /* END FOOTER */ -/* END LAYOUT */ - - -/* UL.SUBNAV */ - ul.subnav { - margin: 0; - padding: 0; - - font-size: 0.8em; - list-style: none; - } - ul.subnav li { - margin: 0 0 1em 0; - padding: 0; - - list-style: none; - } - ul.subnav li a, - ul.subnav li a:link, - ul.subnav li a:visited, - ul.subnav li a:active { - text-decoration: none; - font-weight: bold; - - color: black; - } - ul.subnav li a:hover { - text-decoration: underline; - } - ul.subnav li strong { - padding: 0 0 0 12px; - - background: url("../i/subnav-highlight.gif") left top no-repeat transparent; - } - ul.subnav li strong a, - ul.subnav li strong a:link, - ul.subnav li strong a:visited, - ul.subnav li strong a:active { - color: white; - background-color: black; - } -/* END UL.SUBNAV */ +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* SITE SPECIFIC LAYOUT */ + body { + margin: 0; + padding: 0; + + text-align: center; + + background: white; + } + div#page { + width: 780px; + + margin: 0 auto; + padding: 0; + + text-align: center; + + background: white; + } + + /* HEADER */ + div#header { + margin: 0 0 5em 0; + padding: 40px 20px; + + color: white; + background: black; + + text-align: left; + } + div#branding { + float: left; + width: 40%; + + margin: 0; + padding: 10px 0 10px 20px; + + text-align: left; + } + div#search { + float: right; + width: 49%; + + margin: 0; + padding: 16px 20px 0 0; + + text-align: right; + } + /* END HEADER */ + + + /* CONTENT */ + div#content { + + } + + /* MAIN */ + div#main { + + } + /* END MAIN */ + + /* SUB */ + div#sub { + + } + /* END SUB */ + + /* END CONTENT */ + + + /* FOOTER */ + div#footer { + color: white; + background-color: black; + } + div#footer p { + margin: 0; + padding: 15px; + + font-size: 0.8em; + } + /* END FOOTER */ +/* END LAYOUT */ + + +/* UL.SUBNAV */ + ul.subnav { + margin: 0; + padding: 0; + + font-size: 0.8em; + list-style: none; + } + ul.subnav li { + margin: 0 0 1em 0; + padding: 0; + + list-style: none; + } + ul.subnav li a, + ul.subnav li a:link, + ul.subnav li a:visited, + ul.subnav li a:active { + text-decoration: none; + font-weight: bold; + + color: black; + } + ul.subnav li a:hover { + text-decoration: underline; + } + ul.subnav li strong { + padding: 0 0 0 12px; + + background: url("../i/subnav-highlight.gif") left top no-repeat transparent; + } + ul.subnav li strong a, + ul.subnav li strong a:link, + ul.subnav li strong a:visited, + ul.subnav li strong a:active { + color: white; + background-color: black; + } +/* END UL.SUBNAV */ diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/nav-horizontal.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/nav-horizontal.css index 2af4f2bc..5b9716ab 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/nav-horizontal.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/nav-horizontal.css @@ -1,105 +1,105 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* NAV */ - div#nav { - font-size: 0.8em; - } - * html div#nav { - /* hide ie/mac \*/ - height: 1%; - /* end hide */ - } - div#nav div.wrapper { - position: absolute; - left: 0; - bottom: 0; - width: 100%; - } - div#nav ul { - width: 100%; - - margin: 0; - padding: 0; - - line-height: 1em; - list-style: none; - } - div#nav li { - float: left; - display: inline; - - margin: 0; - padding: 0; - - list-style: none; - - line-height: 1em; - border-right: 1px solid #aaa; - } - div#nav li.last { - border-right: none; - } - div#nav a, - div#nav a:link, - div#nav a:active, - div#nav a:visited { - display: inline-block; - /* hide from ie/mac \*/ - display: block; - /* end hide */ - - margin: 0; - padding: 5px 38px 5px 38px; - - font-weight: bold; - text-decoration: none; - - color: black; - background: #ddd; - } - div#nav a:hover { - text-decoration: underline; - } - div#nav strong { - display: inline-block; - /* hide from ie/mac \*/ - display: block; - /* end hide */ - - color: white; - background: black; - } - div#nav strong a, - div#nav strong a:link, - div#nav strong a:active, - div#nav strong a:visited, - div#nav strong a:hover { - color: white; - background-color: black; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* NAV */ + div#nav { + font-size: 0.8em; + } + * html div#nav { + /* hide ie/mac \*/ + height: 1%; + /* end hide */ + } + div#nav div.wrapper { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + } + div#nav ul { + width: 100%; + + margin: 0; + padding: 0; + + line-height: 1em; + list-style: none; + } + div#nav li { + float: left; + display: inline; + + margin: 0; + padding: 0; + + list-style: none; + + line-height: 1em; + border-right: 1px solid #aaa; + } + div#nav li.last { + border-right: none; + } + div#nav a, + div#nav a:link, + div#nav a:active, + div#nav a:visited { + display: inline-block; + /* hide from ie/mac \*/ + display: block; + /* end hide */ + + margin: 0; + padding: 5px 38px 5px 38px; + + font-weight: bold; + text-decoration: none; + + color: black; + background: #ddd; + } + div#nav a:hover { + text-decoration: underline; + } + div#nav strong { + display: inline-block; + /* hide from ie/mac \*/ + display: block; + /* end hide */ + + color: white; + background: black; + } + div#nav strong a, + div#nav strong a:link, + div#nav strong a:active, + div#nav strong a:visited, + div#nav strong a:hover { + color: white; + background-color: black; + } /* END NAV */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/nav-vertical.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/nav-vertical.css index 56d8f5dc..674ed81a 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/nav-vertical.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/nav-vertical.css @@ -1,104 +1,104 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* NAV */ - div#nav { - font-size: 0.8em; - } - * html div#nav { - /* hide ie/mac \*/ - height: 1%; - /* end hide */ - } - div#nav div.wrapper { - width: 100%; - - background: #ddd; - } - div#nav ul { - width: 100%; - - margin: 0; - padding: 0; - - line-height: 1em; - list-style: none; - } - div#nav li { - display: block; - - margin: 0; - padding: 0; - - list-style: none; - - line-height: 1em; - } - * html div#nav li { - /* hide ie/mac \*/ - height: 1%; - /* end hide */ - } - div#nav li.last { - - } - div#nav a, - div#nav a:link, - div#nav a:active, - div#nav a:visited { - display: block; - - font-weight: bold; - text-decoration: none; - - margin: 0; - padding: 5px 10px 5px 10px; - - color: black; - background: white; - } - div#nav a:hover { - text-decoration: underline; - - color: white; - background: black; - } - div#nav strong { - display: block; - - color: white; - background: black; - } - div#nav strong a, - div#nav strong a:link, - div#nav strong a:active, - div#nav strong a:visited, - div#nav strong a:hover { - color: white; - background-color: black; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* NAV */ + div#nav { + font-size: 0.8em; + } + * html div#nav { + /* hide ie/mac \*/ + height: 1%; + /* end hide */ + } + div#nav div.wrapper { + width: 100%; + + background: #ddd; + } + div#nav ul { + width: 100%; + + margin: 0; + padding: 0; + + line-height: 1em; + list-style: none; + } + div#nav li { + display: block; + + margin: 0; + padding: 0; + + list-style: none; + + line-height: 1em; + } + * html div#nav li { + /* hide ie/mac \*/ + height: 1%; + /* end hide */ + } + div#nav li.last { + + } + div#nav a, + div#nav a:link, + div#nav a:active, + div#nav a:visited { + display: block; + + font-weight: bold; + text-decoration: none; + + margin: 0; + padding: 5px 10px 5px 10px; + + color: black; + background: white; + } + div#nav a:hover { + text-decoration: underline; + + color: white; + background: black; + } + div#nav strong { + display: block; + + color: white; + background: black; + } + div#nav strong a, + div#nav strong a:link, + div#nav strong a:active, + div#nav strong a:visited, + div#nav strong a:hover { + color: white; + background-color: black; + } /* END NAV */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/tools.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/tools.css index 0555cb08..2bc3c556 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/tools.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/tools.css @@ -1,64 +1,64 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* clearing */ - .stretch, - .clear { - clear: both; - height: 1px; - - margin: 0; - padding: 0; - - font-size: 15px; - line-height: 1px; - } - .clearfix:after { - clear: both; - height: 0; - - display: block; - visibility: hidden; - - content: "."; - } - .clearfix {display:inline-block;} - /* Hide from IE Mac \*/ - .clearfix {display:block;} - /* End hide from IE Mac */ -/* end clearing */ - -/* accessibility */ - span.accesskey { - text-decoration: none; - } - .accessibility { - position: absolute; - top: -999em; - left: -999em; - } +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* clearing */ + .stretch, + .clear { + clear: both; + height: 1px; + + margin: 0; + padding: 0; + + font-size: 15px; + line-height: 1px; + } + .clearfix:after { + clear: both; + height: 0; + + display: block; + visibility: hidden; + + content: "."; + } + .clearfix {display:inline-block;} + /* Hide from IE Mac \*/ + .clearfix {display:block;} + /* End hide from IE Mac */ +/* end clearing */ + +/* accessibility */ + span.accesskey { + text-decoration: none; + } + .accessibility { + position: absolute; + top: -999em; + left: -999em; + } /* end accessibility */ \ No newline at end of file diff --git a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/typo.css b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/typo.css index 9f54ab95..10296ffe 100644 --- a/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/typo.css +++ b/spring-js-resources/src/main/resources/META-INF/web-resources/css-framework/css/typo.css @@ -1,228 +1,228 @@ -/* -A CSS Framework by Mike Stenhouse of Content with Style -------------------------------------------------------- - -Copyright (c) 2005, Mike Stenhouse of Content with Style - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* TYPOGRAPHY */ - body { - text-align: left; - font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; - font-size: 76%; - line-height: 1em; - - color: #333; - } - div { - font-size: 1em; - } - img { - border: 0; - } - -/* LINKS */ - a, - a:link, - a:active { - text-decoration: underline; - - color: blue; - background-color: white; - } - a:visited { - color: purple; - background-color: transparent; - } - a:hover { - text-decoration: none; - - color: white; - background-color: black; - } -/* END LINKS */ - -/* HEADINGS */ - h1 { - margin: 0 0 0.5em 0; - padding: 0; - - font-size: 2em; - line-height: 1.5em; - - color: black; - } - h2 { - margin: 0 0 0.5em 0; - padding: 0; - - font-size: 1.5em; - line-height: 1.5em; - - color: black; - } - h3 { - margin: 0 0 0.5em 0; - padding:0; - - font-size: 1.3em; - line-height: 1.3em; - - color: black; - } - h4 { - margin: 0 0 0.25em 0; - padding: 0; - - font-size: 1.2em; - line-height: 1.3em; - - color: black; - } - h5 { - margin: 0 0 0.25em 0; - padding: 0; - - font-size: 1.1em; - line-height: 1.3em; - - color: black; - } - h6 { - margin: 0 0 0.25em 0; - padding: 0; - - font-size: 1em; - line-height: 1.3em; - - color: black; - } -/* END HEADINGS */ - -/* TEXT */ - p { - margin: 0 0 1.5em 0; - padding: 0; - - font-size: 1em; - line-height:1.4em; - } - blockquote { - margin-left: 10px; - - border-left: 10px solid #ddd; - } - pre { - font-family: monospace; - font-size: 1.0em; - } - strong, b { - font-weight: bold; - } - em, i { - font-style:italic; - } - code { - font-family: "Courier New", Courier, monospace; - font-size: 1em; - white-space: pre; - } -/* END TEXT */ - -/* LISTS */ - ul { - margin: 0 0 1.5em 0; - padding: 0; - - line-height:1.4em; - } - ul li { - margin: 0 0 0.25em 30px; - padding: 0; - } - ol { - margin: 0 0 1.5em 0; - padding: 0; - - font-size: 1.0em; - line-height: 1.4em; - } - ol li { - margin: 0 0 0.25em 30px; - padding: 0; - - font-size: 1.0em; - } - dl { - margin: 0 0 1.5em 0; - padding: 0; - - line-height: 1.4em; - } - dl dt { - margin: 0.25em 0 0.25em 0; - padding: 0; - - font-weight: bold; - } - dl dd { - margin: 0 0 0 30px; - padding: 0; - } -/* END LISTS */ - - -/* TABLE */ - table { - margin: 0 0 1.5em 0; - padding: 0; - - font-size: 1em; - } - table caption { - margin: 0; - padding: 0 0 1.5em 0; - - font-weight: bold; - } - th { - font-weight: bold; - text-align: left; - } - td { - font-size: 1em; - } -/* END TABLE */ - - hr { - display: none; - } - div.hr { - height: 1px; - - margin: 1.5em 10px; - - border-bottom: 1px dotted black; - } - +/* +A CSS Framework by Mike Stenhouse of Content with Style +------------------------------------------------------- + +Copyright (c) 2005, Mike Stenhouse of Content with Style + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of CSS Framework nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* TYPOGRAPHY */ + body { + text-align: left; + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 76%; + line-height: 1em; + + color: #333; + } + div { + font-size: 1em; + } + img { + border: 0; + } + +/* LINKS */ + a, + a:link, + a:active { + text-decoration: underline; + + color: blue; + background-color: white; + } + a:visited { + color: purple; + background-color: transparent; + } + a:hover { + text-decoration: none; + + color: white; + background-color: black; + } +/* END LINKS */ + +/* HEADINGS */ + h1 { + margin: 0 0 0.5em 0; + padding: 0; + + font-size: 2em; + line-height: 1.5em; + + color: black; + } + h2 { + margin: 0 0 0.5em 0; + padding: 0; + + font-size: 1.5em; + line-height: 1.5em; + + color: black; + } + h3 { + margin: 0 0 0.5em 0; + padding:0; + + font-size: 1.3em; + line-height: 1.3em; + + color: black; + } + h4 { + margin: 0 0 0.25em 0; + padding: 0; + + font-size: 1.2em; + line-height: 1.3em; + + color: black; + } + h5 { + margin: 0 0 0.25em 0; + padding: 0; + + font-size: 1.1em; + line-height: 1.3em; + + color: black; + } + h6 { + margin: 0 0 0.25em 0; + padding: 0; + + font-size: 1em; + line-height: 1.3em; + + color: black; + } +/* END HEADINGS */ + +/* TEXT */ + p { + margin: 0 0 1.5em 0; + padding: 0; + + font-size: 1em; + line-height:1.4em; + } + blockquote { + margin-left: 10px; + + border-left: 10px solid #ddd; + } + pre { + font-family: monospace; + font-size: 1.0em; + } + strong, b { + font-weight: bold; + } + em, i { + font-style:italic; + } + code { + font-family: "Courier New", Courier, monospace; + font-size: 1em; + white-space: pre; + } +/* END TEXT */ + +/* LISTS */ + ul { + margin: 0 0 1.5em 0; + padding: 0; + + line-height:1.4em; + } + ul li { + margin: 0 0 0.25em 30px; + padding: 0; + } + ol { + margin: 0 0 1.5em 0; + padding: 0; + + font-size: 1.0em; + line-height: 1.4em; + } + ol li { + margin: 0 0 0.25em 30px; + padding: 0; + + font-size: 1.0em; + } + dl { + margin: 0 0 1.5em 0; + padding: 0; + + line-height: 1.4em; + } + dl dt { + margin: 0.25em 0 0.25em 0; + padding: 0; + + font-weight: bold; + } + dl dd { + margin: 0 0 0 30px; + padding: 0; + } +/* END LISTS */ + + +/* TABLE */ + table { + margin: 0 0 1.5em 0; + padding: 0; + + font-size: 1em; + } + table caption { + margin: 0; + padding: 0 0 1.5em 0; + + font-weight: bold; + } + th { + font-weight: bold; + text-align: left; + } + td { + font-size: 1em; + } +/* END TABLE */ + + hr { + display: none; + } + div.hr { + height: 1px; + + margin: 1.5em 10px; + + border-bottom: 1px dotted black; + } + /* END TYPOGRAPHY */ \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/action/EvaluateAction.java b/spring-webflow/src/main/java/org/springframework/webflow/action/EvaluateAction.java index 0b03879c..63c6bb31 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/action/EvaluateAction.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/action/EvaluateAction.java @@ -1,113 +1,113 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.action; - -import org.springframework.binding.expression.Expression; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.webflow.execution.Action; -import org.springframework.webflow.execution.ActionExecutor; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.RequestContext; - -/** - * An action that evaluates an expression and optionally exposes its result. - *

- * Delegates to a {@link ResultEventFactory} to determine how to map the evaluation result to an action outcome - * {@link Event}. - * - * @see Expression - * @see ResultEventFactory - * - * @author Keith Donald - * @author Jeremy Grelle - */ -public class EvaluateAction extends AbstractAction { - - /** - * The expression to evaluate when this action is invoked. Required. - */ - private Expression expression; - - /** - * The expression to evaluate to set the result of the action. Optional. - */ - private Expression resultExpression; - - /** - * The selector for the factory that will create the action result event callers can respond to. - */ - private ResultEventFactory resultEventFactory; - - /** - * Create a new evaluate action. - * @param expression the expression to evaluate (required) - * @param resultExpression the expression to evaluate the result (optional) - */ - public EvaluateAction(Expression expression, Expression resultExpression) { - init(expression, resultExpression, null); - } - - /** - * Create a new evaluate action. - * @param expression the expression to evaluate (required) - * @param resultExpression the strategy for how the expression result will be exposed to the flow (optional) - * @param resultEventFactory the factory that will map the evaluation result to a Web Flow event (optional) - */ - public EvaluateAction(Expression expression, Expression resultExpression, ResultEventFactory resultEventFactory) { - init(expression, resultExpression, resultEventFactory); - } - - protected Event doExecute(RequestContext context) throws Exception { - Object result = expression.getValue(context); - if (result instanceof Action) { - return ActionExecutor.execute((Action) result, context); - } else { - if (resultExpression != null) { - resultExpression.setValue(context, result); - } - return resultEventFactory.createResultEvent(this, result, context); - } - } - - public String toString() { - return new ToStringCreator(this).append("expression", expression).append("resultExpression", resultExpression) - .toString(); - } - - // internal helpers - - private void init(Expression expression, Expression resultExpression, ResultEventFactory resultEventFactory) { - Assert.notNull(expression, "The expression this action should evaluate is required"); - this.expression = expression; - this.resultExpression = resultExpression; - this.resultEventFactory = resultEventFactory != null ? resultEventFactory : new DefaultResultEventFactory(); - } - - /** - * Default implementation that uses the ResultEventFactorySelector helper. - * @author Keith Donald - */ - private class DefaultResultEventFactory implements ResultEventFactory { - - private ResultEventFactorySelector selector = new ResultEventFactorySelector(); - - public Event createResultEvent(Object source, Object resultObject, RequestContext context) { - return selector.forResult(resultObject).createResultEvent(source, resultObject, context); - } - } - +/* + * Copyright 2004-2012 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 + * + * https://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.action; + +import org.springframework.binding.expression.Expression; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.webflow.execution.Action; +import org.springframework.webflow.execution.ActionExecutor; +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.execution.RequestContext; + +/** + * An action that evaluates an expression and optionally exposes its result. + *

+ * Delegates to a {@link ResultEventFactory} to determine how to map the evaluation result to an action outcome + * {@link Event}. + * + * @see Expression + * @see ResultEventFactory + * + * @author Keith Donald + * @author Jeremy Grelle + */ +public class EvaluateAction extends AbstractAction { + + /** + * The expression to evaluate when this action is invoked. Required. + */ + private Expression expression; + + /** + * The expression to evaluate to set the result of the action. Optional. + */ + private Expression resultExpression; + + /** + * The selector for the factory that will create the action result event callers can respond to. + */ + private ResultEventFactory resultEventFactory; + + /** + * Create a new evaluate action. + * @param expression the expression to evaluate (required) + * @param resultExpression the expression to evaluate the result (optional) + */ + public EvaluateAction(Expression expression, Expression resultExpression) { + init(expression, resultExpression, null); + } + + /** + * Create a new evaluate action. + * @param expression the expression to evaluate (required) + * @param resultExpression the strategy for how the expression result will be exposed to the flow (optional) + * @param resultEventFactory the factory that will map the evaluation result to a Web Flow event (optional) + */ + public EvaluateAction(Expression expression, Expression resultExpression, ResultEventFactory resultEventFactory) { + init(expression, resultExpression, resultEventFactory); + } + + protected Event doExecute(RequestContext context) throws Exception { + Object result = expression.getValue(context); + if (result instanceof Action) { + return ActionExecutor.execute((Action) result, context); + } else { + if (resultExpression != null) { + resultExpression.setValue(context, result); + } + return resultEventFactory.createResultEvent(this, result, context); + } + } + + public String toString() { + return new ToStringCreator(this).append("expression", expression).append("resultExpression", resultExpression) + .toString(); + } + + // internal helpers + + private void init(Expression expression, Expression resultExpression, ResultEventFactory resultEventFactory) { + Assert.notNull(expression, "The expression this action should evaluate is required"); + this.expression = expression; + this.resultExpression = resultExpression; + this.resultEventFactory = resultEventFactory != null ? resultEventFactory : new DefaultResultEventFactory(); + } + + /** + * Default implementation that uses the ResultEventFactorySelector helper. + * @author Keith Donald + */ + private class DefaultResultEventFactory implements ResultEventFactory { + + private ResultEventFactorySelector selector = new ResultEventFactorySelector(); + + public Event createResultEvent(Object source, Object resultObject, RequestContext context) { + return selector.forResult(resultObject).createResultEvent(source, resultObject, context); + } + } + } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/action/EventFactorySupport.java b/spring-webflow/src/main/java/org/springframework/webflow/action/EventFactorySupport.java index e49bda83..0d7f1573 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/action/EventFactorySupport.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/action/EventFactorySupport.java @@ -1,257 +1,257 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.action; - -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.core.collection.CollectionUtils; -import org.springframework.webflow.execution.Event; - -/** - * A convenience support class assisting in the creation of {@link Event} objects. - *

- * This class can be used as a simple utility class when you need to create common event objects. Alternatively you - * could extend it as a base support class when creating custom event factories. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class EventFactorySupport { - - /** - * The default 'success' result event identifier ("success"). - */ - private static final String SUCCESS_EVENT_ID = "success"; - - /** - * The default 'error' result event identifier ("error"). - */ - private static final String ERROR_EVENT_ID = "error"; - - /** - * The default 'yes' result event identifier ("yes"). - */ - private static final String YES_EVENT_ID = "yes"; - - /** - * The default 'no' result event identifier ("no"). - */ - private static final String NO_EVENT_ID = "no"; - - /** - * The default 'null' result event identifier ("null"). - */ - private static final String NULL_EVENT_ID = "null"; - - /** - * The default 'exception' event attribute name ("exception"). - */ - private static final String EXCEPTION_ATTRIBUTE_NAME = "exception"; - - /** - * The default 'result' event attribute name ("result"). - */ - private static final String RESULT_ATTRIBUTE_NAME = "result"; - - /** - * The success event identifier. - */ - private String successEventId = SUCCESS_EVENT_ID; - - /** - * The error event identifier. - */ - private String errorEventId = ERROR_EVENT_ID; - - /** - * The yes event identifier. - */ - private String yesEventId = YES_EVENT_ID; - - /** - * The no event identifier. - */ - private String noEventId = NO_EVENT_ID; - - /** - * The null event identifier. - */ - private String nullEventId = NULL_EVENT_ID; - - /** - * The exception event attribute name. - */ - private String exceptionAttributeName = EXCEPTION_ATTRIBUTE_NAME; - - /** - * The result event attribute name. - */ - private String resultAttributeName = RESULT_ATTRIBUTE_NAME; - - public String getSuccessEventId() { - return successEventId; - } - - public void setSuccessEventId(String successEventId) { - this.successEventId = successEventId; - } - - public String getErrorEventId() { - return errorEventId; - } - - public void setErrorEventId(String errorEventId) { - this.errorEventId = errorEventId; - } - - public String getYesEventId() { - return yesEventId; - } - - public void setYesEventId(String yesEventId) { - this.yesEventId = yesEventId; - } - - public String getNoEventId() { - return noEventId; - } - - public void setNoEventId(String noEventId) { - this.noEventId = noEventId; - } - - public String getNullEventId() { - return nullEventId; - } - - public void setNullEventId(String nullEventId) { - this.nullEventId = nullEventId; - } - - public String getExceptionAttributeName() { - return exceptionAttributeName; - } - - public void setExceptionAttributeName(String exceptionAttributeName) { - this.exceptionAttributeName = exceptionAttributeName; - } - - public String getResultAttributeName() { - return resultAttributeName; - } - - public void setResultAttributeName(String resultAttributeName) { - this.resultAttributeName = resultAttributeName; - } - - /** - * Returns a "success" event. - * @param source the source of the event - */ - public Event success(Object source) { - return event(source, getSuccessEventId()); - } - - /** - * Returns a "success" event with the provided result object as an attribute. The result object is identified by the - * attribute name {@link #getResultAttributeName()}. - * @param source the source of the event - * @param result the action success result - */ - public Event success(Object source, Object result) { - return event(source, getSuccessEventId(), getResultAttributeName(), result); - } - - /** - * Returns an "error" event. - * @param source the source of the event - */ - public Event error(Object source) { - return event(source, getErrorEventId()); - } - - /** - * Returns an "error" event caused by the provided exception. - * @param source the source of the event - * @param e the exception that caused the error event, to be put as an event attribute under the name - * {@link #getExceptionAttributeName()} - */ - public Event error(Object source, Exception e) { - return event(source, getErrorEventId(), getExceptionAttributeName(), e); - } - - /** - * Returns a "yes" event. - * @param source the source of the event - */ - public Event yes(Object source) { - return event(source, getYesEventId()); - } - - /** - * Returns a "no" result event. - * @param source the source of the event - */ - public Event no(Object source) { - return event(source, getNoEventId()); - } - - /** - * Returns an event to communicate an occurrence of a boolean expression. - * @param source the source of the event - * @param booleanResult the boolean - * @return yes or no - */ - public Event event(Object source, boolean booleanResult) { - if (booleanResult) { - return yes(source); - } else { - return no(source); - } - } - - /** - * Returns a event with the specified identifier. - * @param source the source of the event - * @param eventId the result event identifier - * @return the event - */ - public Event event(Object source, String eventId) { - return new Event(source, eventId, null); - } - - /** - * Returns a event with the specified identifier and the specified set of attributes. - * @param source the source of the event - * @param eventId the result event identifier - * @param attributes the event payload attributes - * @return the event - */ - public Event event(Object source, String eventId, AttributeMap attributes) { - return new Event(source, eventId, attributes); - } - - /** - * Returns a result event with the specified identifier and a single attribute. - * @param source the source of the event - * @param eventId the result id - * @param attributeName the attribute name - * @param attributeValue the attribute value - * @return the event - */ - public Event event(Object source, String eventId, String attributeName, Object attributeValue) { - return new Event(source, eventId, CollectionUtils.singleEntryMap(attributeName, attributeValue)); - } +/* + * Copyright 2004-2012 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 + * + * https://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.action; + +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.core.collection.CollectionUtils; +import org.springframework.webflow.execution.Event; + +/** + * A convenience support class assisting in the creation of {@link Event} objects. + *

+ * This class can be used as a simple utility class when you need to create common event objects. Alternatively you + * could extend it as a base support class when creating custom event factories. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class EventFactorySupport { + + /** + * The default 'success' result event identifier ("success"). + */ + private static final String SUCCESS_EVENT_ID = "success"; + + /** + * The default 'error' result event identifier ("error"). + */ + private static final String ERROR_EVENT_ID = "error"; + + /** + * The default 'yes' result event identifier ("yes"). + */ + private static final String YES_EVENT_ID = "yes"; + + /** + * The default 'no' result event identifier ("no"). + */ + private static final String NO_EVENT_ID = "no"; + + /** + * The default 'null' result event identifier ("null"). + */ + private static final String NULL_EVENT_ID = "null"; + + /** + * The default 'exception' event attribute name ("exception"). + */ + private static final String EXCEPTION_ATTRIBUTE_NAME = "exception"; + + /** + * The default 'result' event attribute name ("result"). + */ + private static final String RESULT_ATTRIBUTE_NAME = "result"; + + /** + * The success event identifier. + */ + private String successEventId = SUCCESS_EVENT_ID; + + /** + * The error event identifier. + */ + private String errorEventId = ERROR_EVENT_ID; + + /** + * The yes event identifier. + */ + private String yesEventId = YES_EVENT_ID; + + /** + * The no event identifier. + */ + private String noEventId = NO_EVENT_ID; + + /** + * The null event identifier. + */ + private String nullEventId = NULL_EVENT_ID; + + /** + * The exception event attribute name. + */ + private String exceptionAttributeName = EXCEPTION_ATTRIBUTE_NAME; + + /** + * The result event attribute name. + */ + private String resultAttributeName = RESULT_ATTRIBUTE_NAME; + + public String getSuccessEventId() { + return successEventId; + } + + public void setSuccessEventId(String successEventId) { + this.successEventId = successEventId; + } + + public String getErrorEventId() { + return errorEventId; + } + + public void setErrorEventId(String errorEventId) { + this.errorEventId = errorEventId; + } + + public String getYesEventId() { + return yesEventId; + } + + public void setYesEventId(String yesEventId) { + this.yesEventId = yesEventId; + } + + public String getNoEventId() { + return noEventId; + } + + public void setNoEventId(String noEventId) { + this.noEventId = noEventId; + } + + public String getNullEventId() { + return nullEventId; + } + + public void setNullEventId(String nullEventId) { + this.nullEventId = nullEventId; + } + + public String getExceptionAttributeName() { + return exceptionAttributeName; + } + + public void setExceptionAttributeName(String exceptionAttributeName) { + this.exceptionAttributeName = exceptionAttributeName; + } + + public String getResultAttributeName() { + return resultAttributeName; + } + + public void setResultAttributeName(String resultAttributeName) { + this.resultAttributeName = resultAttributeName; + } + + /** + * Returns a "success" event. + * @param source the source of the event + */ + public Event success(Object source) { + return event(source, getSuccessEventId()); + } + + /** + * Returns a "success" event with the provided result object as an attribute. The result object is identified by the + * attribute name {@link #getResultAttributeName()}. + * @param source the source of the event + * @param result the action success result + */ + public Event success(Object source, Object result) { + return event(source, getSuccessEventId(), getResultAttributeName(), result); + } + + /** + * Returns an "error" event. + * @param source the source of the event + */ + public Event error(Object source) { + return event(source, getErrorEventId()); + } + + /** + * Returns an "error" event caused by the provided exception. + * @param source the source of the event + * @param e the exception that caused the error event, to be put as an event attribute under the name + * {@link #getExceptionAttributeName()} + */ + public Event error(Object source, Exception e) { + return event(source, getErrorEventId(), getExceptionAttributeName(), e); + } + + /** + * Returns a "yes" event. + * @param source the source of the event + */ + public Event yes(Object source) { + return event(source, getYesEventId()); + } + + /** + * Returns a "no" result event. + * @param source the source of the event + */ + public Event no(Object source) { + return event(source, getNoEventId()); + } + + /** + * Returns an event to communicate an occurrence of a boolean expression. + * @param source the source of the event + * @param booleanResult the boolean + * @return yes or no + */ + public Event event(Object source, boolean booleanResult) { + if (booleanResult) { + return yes(source); + } else { + return no(source); + } + } + + /** + * Returns a event with the specified identifier. + * @param source the source of the event + * @param eventId the result event identifier + * @return the event + */ + public Event event(Object source, String eventId) { + return new Event(source, eventId, null); + } + + /** + * Returns a event with the specified identifier and the specified set of attributes. + * @param source the source of the event + * @param eventId the result event identifier + * @param attributes the event payload attributes + * @return the event + */ + public Event event(Object source, String eventId, AttributeMap attributes) { + return new Event(source, eventId, attributes); + } + + /** + * Returns a result event with the specified identifier and a single attribute. + * @param source the source of the event + * @param eventId the result id + * @param attributeName the attribute name + * @param attributeValue the attribute value + * @return the event + */ + public Event event(Object source, String eventId, String attributeName, Object attributeValue) { + return new Event(source, eventId, CollectionUtils.singleEntryMap(attributeName, attributeValue)); + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/action/RenderAction.java b/spring-webflow/src/main/java/org/springframework/webflow/action/RenderAction.java index f21b9554..c3ab487b 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/action/RenderAction.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/action/RenderAction.java @@ -1,62 +1,62 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.action; - -import org.springframework.binding.expression.Expression; -import org.springframework.core.style.ToStringCreator; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.View; - -/** - * An action that sets a special attribute that views use to render partial views called "fragments", instead of the - * entire view. - * - * @author Keith Donald - */ -public class RenderAction extends AbstractAction { - - /** - * The expression for setting the scoped attribute value. - */ - private Expression[] fragmentExpressions; - - /** - * Creates a new render action. - * @param fragmentExpressions the set of expressions to resolve the view fragments to render - */ - public RenderAction(Expression... fragmentExpressions) { - if (fragmentExpressions == null || fragmentExpressions.length == 0) { - throw new IllegalArgumentException( - "You must provide at least one fragment expression to this render action"); - } - this.fragmentExpressions = fragmentExpressions; - } - - protected Event doExecute(RequestContext context) throws Exception { - String[] fragments = new String[fragmentExpressions.length]; - for (int i = 0; i < fragmentExpressions.length; i++) { - Expression exp = fragmentExpressions[i]; - fragments[i] = (String) exp.getValue(context); - } - context.getFlashScope().put(View.RENDER_FRAGMENTS_ATTRIBUTE, fragments); - return success(); - } - - public String toString() { - return new ToStringCreator(this).append("fragments", fragmentExpressions).toString(); - } +/* + * Copyright 2004-2012 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 + * + * https://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.action; + +import org.springframework.binding.expression.Expression; +import org.springframework.core.style.ToStringCreator; +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.View; + +/** + * An action that sets a special attribute that views use to render partial views called "fragments", instead of the + * entire view. + * + * @author Keith Donald + */ +public class RenderAction extends AbstractAction { + + /** + * The expression for setting the scoped attribute value. + */ + private Expression[] fragmentExpressions; + + /** + * Creates a new render action. + * @param fragmentExpressions the set of expressions to resolve the view fragments to render + */ + public RenderAction(Expression... fragmentExpressions) { + if (fragmentExpressions == null || fragmentExpressions.length == 0) { + throw new IllegalArgumentException( + "You must provide at least one fragment expression to this render action"); + } + this.fragmentExpressions = fragmentExpressions; + } + + protected Event doExecute(RequestContext context) throws Exception { + String[] fragments = new String[fragmentExpressions.length]; + for (int i = 0; i < fragmentExpressions.length; i++) { + Expression exp = fragmentExpressions[i]; + fragments[i] = (String) exp.getValue(context); + } + context.getFlashScope().put(View.RENDER_FRAGMENTS_ATTRIBUTE, fragments); + return success(); + } + + public String toString() { + return new ToStringCreator(this).append("fragments", fragmentExpressions).toString(); + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/action/ResultEventFactorySelector.java b/spring-webflow/src/main/java/org/springframework/webflow/action/ResultEventFactorySelector.java index 49a2d15d..90b332ba 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/action/ResultEventFactorySelector.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/action/ResultEventFactorySelector.java @@ -1,77 +1,77 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.action; - -import java.lang.reflect.Method; - -/** - * Helper that selects the {@link ResultEventFactory} to use for a particular result object. - * - * @see EvaluateAction - * - * @author Keith Donald - */ -public class ResultEventFactorySelector { - - /** - * The event factory instance for mapping a return value to a success event. - */ - private SuccessEventFactory successEventFactory = new SuccessEventFactory(); - - /** - * The event factory instance for mapping a result object to an event, using the type of the result object as the - * mapping criteria. - */ - private ResultObjectBasedEventFactory resultObjectBasedEventFactory = new ResultObjectBasedEventFactory(); - - /** - * Select the appropriate result event factory for attempts to invoke the given method. - * @param method the method - * @return the result event factory - */ - public ResultEventFactory forMethod(Method method) { - return forType(method.getReturnType()); - } - - /** - * Select the appropriate result event factory for the given result. - * @param result the result - * @return the result event factory - */ - public ResultEventFactory forResult(Object result) { - if (result == null) { - return successEventFactory; - } else { - return forType(result.getClass()); - } - } - - /** - * Select the appropriate result event factory for given result type. This implementation returns - * {@link ResultObjectBasedEventFactory} if the type is - * {@link ResultObjectBasedEventFactory#isMappedValueType(Class) mapped} by that result event factory, otherwise - * {@link SuccessEventFactory} is returned. - * @param resultType the result type - * @return the result event factory - */ - protected ResultEventFactory forType(Class resultType) { - if (resultObjectBasedEventFactory.isMappedValueType(resultType)) { - return resultObjectBasedEventFactory; - } else { - return successEventFactory; - } - } +/* + * Copyright 2004-2012 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 + * + * https://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.action; + +import java.lang.reflect.Method; + +/** + * Helper that selects the {@link ResultEventFactory} to use for a particular result object. + * + * @see EvaluateAction + * + * @author Keith Donald + */ +public class ResultEventFactorySelector { + + /** + * The event factory instance for mapping a return value to a success event. + */ + private SuccessEventFactory successEventFactory = new SuccessEventFactory(); + + /** + * The event factory instance for mapping a result object to an event, using the type of the result object as the + * mapping criteria. + */ + private ResultObjectBasedEventFactory resultObjectBasedEventFactory = new ResultObjectBasedEventFactory(); + + /** + * Select the appropriate result event factory for attempts to invoke the given method. + * @param method the method + * @return the result event factory + */ + public ResultEventFactory forMethod(Method method) { + return forType(method.getReturnType()); + } + + /** + * Select the appropriate result event factory for the given result. + * @param result the result + * @return the result event factory + */ + public ResultEventFactory forResult(Object result) { + if (result == null) { + return successEventFactory; + } else { + return forType(result.getClass()); + } + } + + /** + * Select the appropriate result event factory for given result type. This implementation returns + * {@link ResultObjectBasedEventFactory} if the type is + * {@link ResultObjectBasedEventFactory#isMappedValueType(Class) mapped} by that result event factory, otherwise + * {@link SuccessEventFactory} is returned. + * @param resultType the result type + * @return the result event factory + */ + protected ResultEventFactory forType(Class resultType) { + if (resultObjectBasedEventFactory.isMappedValueType(resultType)) { + return resultObjectBasedEventFactory; + } else { + return successEventFactory; + } + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/action/SetAction.java b/spring-webflow/src/main/java/org/springframework/webflow/action/SetAction.java index 4e396f81..596c49a4 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/action/SetAction.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/action/SetAction.java @@ -1,64 +1,64 @@ -/* - * 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 - * - * https://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.action; - -import org.springframework.binding.expression.Expression; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.ScopeType; - -/** - * An action that sets an attribute in a {@link ScopeType scope} when executed. Always returns the "success" event. - * - * @author Keith Donald - */ -public class SetAction extends AbstractAction { - - /** - * The expression for setting the scoped attribute value. - */ - private Expression nameExpression; - - /** - * The expression for resolving the scoped attribute value. - */ - private Expression valueExpression; - - /** - * Creates a new set attribute action. - * @param nameExpression the name of the property to set (required) - * @param valueExpression the expression to obtain the new property value (required) expected - */ - public SetAction(Expression nameExpression, Expression valueExpression) { - Assert.notNull(nameExpression, "The name expression is required"); - Assert.notNull(valueExpression, "The value expression is required"); - this.nameExpression = nameExpression; - this.valueExpression = valueExpression; - } - - protected Event doExecute(RequestContext context) throws Exception { - Object value = valueExpression.getValue(context); - nameExpression.setValue(context, value); - return success(); - } - - public String toString() { - return new ToStringCreator(this).append("name", nameExpression).append("value", valueExpression).toString(); - } - +/* + * 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 + * + * https://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.action; + +import org.springframework.binding.expression.Expression; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.ScopeType; + +/** + * An action that sets an attribute in a {@link ScopeType scope} when executed. Always returns the "success" event. + * + * @author Keith Donald + */ +public class SetAction extends AbstractAction { + + /** + * The expression for setting the scoped attribute value. + */ + private Expression nameExpression; + + /** + * The expression for resolving the scoped attribute value. + */ + private Expression valueExpression; + + /** + * Creates a new set attribute action. + * @param nameExpression the name of the property to set (required) + * @param valueExpression the expression to obtain the new property value (required) expected + */ + public SetAction(Expression nameExpression, Expression valueExpression) { + Assert.notNull(nameExpression, "The name expression is required"); + Assert.notNull(valueExpression, "The value expression is required"); + this.nameExpression = nameExpression; + this.valueExpression = valueExpression; + } + + protected Event doExecute(RequestContext context) throws Exception { + Object value = valueExpression.getValue(context); + nameExpression.setValue(context, value); + return success(); + } + + public String toString() { + return new ToStringCreator(this).append("name", nameExpression).append("value", valueExpression).toString(); + } + } \ No newline at end of file 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 c705556b..2accefcc 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 @@ -1,246 +1,246 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.config; - -import java.util.Set; - -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.binding.convert.ConversionExecutor; -import org.springframework.binding.convert.ConversionService; -import org.springframework.binding.convert.service.DefaultConversionService; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.webflow.conversation.ConversationManager; -import org.springframework.webflow.conversation.impl.SessionBindingConversationManager; -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.core.collection.LocalAttributeMap; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.registry.FlowDefinitionLocator; -import org.springframework.webflow.definition.registry.FlowDefinitionRegistry; -import org.springframework.webflow.engine.impl.FlowExecutionImplFactory; -import org.springframework.webflow.execution.FlowExecutionFactory; -import org.springframework.webflow.execution.factory.FlowExecutionListenerLoader; -import org.springframework.webflow.execution.repository.FlowExecutionRepository; -import org.springframework.webflow.execution.repository.impl.DefaultFlowExecutionRepository; -import org.springframework.webflow.execution.repository.snapshot.FlowExecutionSnapshotFactory; -import org.springframework.webflow.execution.repository.snapshot.SerializedFlowExecutionSnapshotFactory; -import org.springframework.webflow.execution.repository.snapshot.SimpleFlowExecutionSnapshotFactory; -import org.springframework.webflow.executor.FlowExecutor; -import org.springframework.webflow.executor.FlowExecutorImpl; - -/** - * This factory encapsulates the construction and assembly of a {@link FlowExecutor}, including the provision of its - * {@link FlowExecutionRepository} strategy. As a FactoryBean, this class has been designed for use as a - * Spring managed bean. - *

- * The definition locator property is required, all other properties are optional. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -class FlowExecutorFactoryBean implements FactoryBean, BeanClassLoaderAware, InitializingBean { - - private static final String ALWAYS_REDIRECT_ON_PAUSE = "alwaysRedirectOnPause"; - - private static final String REDIRECT_IN_SAME_STATE = "redirectInSameState"; - - private FlowDefinitionLocator flowDefinitionLocator; - - private Integer maxFlowExecutions; - - private Integer maxFlowExecutionSnapshots; - - private Set flowExecutionAttributes; - - private FlowExecutionListenerLoader flowExecutionListenerLoader; - - private ConversationManager conversationManager; - - private ConversionService conversionService; - - private FlowExecutor flowExecutor; - - private ClassLoader classLoader; - - /** - * Sets the flow definition locator that will locate flow definitions needed for execution. Typically also a - * {@link FlowDefinitionRegistry}. Required. - * @param flowDefinitionLocator the flow definition locator (registry) - */ - public void setFlowDefinitionLocator(FlowDefinitionLocator flowDefinitionLocator) { - this.flowDefinitionLocator = flowDefinitionLocator; - } - - /** - * Set the maximum number of allowed flow executions allowed per user. - */ - public void setMaxFlowExecutions(int maxFlowExecutions) { - this.maxFlowExecutions = maxFlowExecutions; - } - - /** - * Set the maximum number of history snapshots allowed per flow execution. - */ - public void setMaxFlowExecutionSnapshots(int maxFlowExecutionSnapshots) { - this.maxFlowExecutionSnapshots = maxFlowExecutionSnapshots; - } - - /** - * Sets the system attributes that apply to flow executions launched by the executor created by this factory. - * Execution attributes may affect flow execution behavior. - * @param flowExecutionAttributes the flow execution system attributes - */ - public void setFlowExecutionAttributes(Set flowExecutionAttributes) { - this.flowExecutionAttributes = flowExecutionAttributes; - } - - /** - * Sets the strategy for loading the listeners that will observe executions of a flow definition. Allows full - * control over what listeners should apply to executions of a flow definition launched by the executor created by - * this factory. - */ - public void setFlowExecutionListenerLoader(FlowExecutionListenerLoader flowExecutionListenerLoader) { - this.flowExecutionListenerLoader = flowExecutionListenerLoader; - } - - /** - * Sets the service type that manages conversations and effectively controls how state is stored physically when a - * flow execution is paused. - */ - public void setConversationManager(ConversationManager conversationManager) { - this.conversationManager = conversationManager; - } - - // implement BeanClassLoaderAware - - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - // implementing InitializingBean - - public void afterPropertiesSet() throws Exception { - Assert.notNull(flowDefinitionLocator, "The flow definition locator property is required"); - if (conversionService == null) { - conversionService = new DefaultConversionService(); - } - MutableAttributeMap executionAttributes = createFlowExecutionAttributes(); - FlowExecutionImplFactory executionFactory = createFlowExecutionFactory(executionAttributes); - DefaultFlowExecutionRepository executionRepository = createFlowExecutionRepository(executionFactory); - executionFactory.setExecutionKeyFactory(executionRepository); - flowExecutor = new FlowExecutorImpl(flowDefinitionLocator, executionFactory, executionRepository); - } - - // implementing FactoryBean - - public Class getObjectType() { - return FlowExecutor.class; - } - - public boolean isSingleton() { - return true; - } - - public FlowExecutor getObject() throws Exception { - return flowExecutor; - } - - private MutableAttributeMap createFlowExecutionAttributes() { - LocalAttributeMap executionAttributes = new LocalAttributeMap<>(); - if (flowExecutionAttributes != null) { - for (FlowElementAttribute attribute : flowExecutionAttributes) { - executionAttributes.put(attribute.getName(), getConvertedValue(attribute)); - } - } - putDefaultFlowExecutionAttributes(executionAttributes); - return executionAttributes; - } - - private void putDefaultFlowExecutionAttributes(LocalAttributeMap executionAttributes) { - if (!executionAttributes.contains(ALWAYS_REDIRECT_ON_PAUSE)) { - executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, true); - } - if (!executionAttributes.contains(REDIRECT_IN_SAME_STATE)) { - executionAttributes.put(REDIRECT_IN_SAME_STATE, true); - } - } - - private DefaultFlowExecutionRepository createFlowExecutionRepository(FlowExecutionFactory executionFactory) { - ConversationManager conversationManager = createConversationManager(); - FlowExecutionSnapshotFactory snapshotFactory = createFlowExecutionSnapshotFactory(executionFactory); - DefaultFlowExecutionRepository rep = new DefaultFlowExecutionRepository(conversationManager, snapshotFactory); - if (maxFlowExecutionSnapshots != null) { - rep.setMaxSnapshots(maxFlowExecutionSnapshots); - } - return rep; - } - - private ConversationManager createConversationManager() { - if (conversationManager == null) { - conversationManager = new SessionBindingConversationManager(); - if (maxFlowExecutions != null) { - ((SessionBindingConversationManager) conversationManager).setMaxConversations(maxFlowExecutions); - } - } - return this.conversationManager; - } - - private FlowExecutionSnapshotFactory createFlowExecutionSnapshotFactory(FlowExecutionFactory executionFactory) { - if (maxFlowExecutionSnapshots != null && maxFlowExecutionSnapshots == 0) { - maxFlowExecutionSnapshots = 1; - return new SimpleFlowExecutionSnapshotFactory(executionFactory, flowDefinitionLocator); - } else { - return new SerializedFlowExecutionSnapshotFactory(executionFactory, flowDefinitionLocator); - } - } - - private FlowExecutionImplFactory createFlowExecutionFactory(AttributeMap executionAttributes) { - FlowExecutionImplFactory executionFactory = new FlowExecutionImplFactory(); - executionFactory.setExecutionAttributes(executionAttributes); - if (flowExecutionListenerLoader != null) { - executionFactory.setExecutionListenerLoader(flowExecutionListenerLoader); - } - return executionFactory; - } - - // utility methods - - private Object getConvertedValue(FlowElementAttribute attribute) { - if (attribute.needsTypeConversion()) { - Class targetType = fromStringToClass(attribute.getType()); - ConversionExecutor converter = conversionService.getConversionExecutor(String.class, targetType); - return converter.execute(attribute.getValue()); - } else { - return attribute.getValue(); - } - } - - private Class fromStringToClass(String name) { - Class clazz = conversionService.getClassForAlias(name); - if (clazz != null) { - return clazz; - } else { - try { - return ClassUtils.forName(name, classLoader); - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("Unable to load class '" + name + "'"); - } - } - } - -} +/* + * Copyright 2004-2012 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 + * + * https://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.config; + +import java.util.Set; + +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.binding.convert.ConversionExecutor; +import org.springframework.binding.convert.ConversionService; +import org.springframework.binding.convert.service.DefaultConversionService; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.webflow.conversation.ConversationManager; +import org.springframework.webflow.conversation.impl.SessionBindingConversationManager; +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.core.collection.LocalAttributeMap; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.registry.FlowDefinitionLocator; +import org.springframework.webflow.definition.registry.FlowDefinitionRegistry; +import org.springframework.webflow.engine.impl.FlowExecutionImplFactory; +import org.springframework.webflow.execution.FlowExecutionFactory; +import org.springframework.webflow.execution.factory.FlowExecutionListenerLoader; +import org.springframework.webflow.execution.repository.FlowExecutionRepository; +import org.springframework.webflow.execution.repository.impl.DefaultFlowExecutionRepository; +import org.springframework.webflow.execution.repository.snapshot.FlowExecutionSnapshotFactory; +import org.springframework.webflow.execution.repository.snapshot.SerializedFlowExecutionSnapshotFactory; +import org.springframework.webflow.execution.repository.snapshot.SimpleFlowExecutionSnapshotFactory; +import org.springframework.webflow.executor.FlowExecutor; +import org.springframework.webflow.executor.FlowExecutorImpl; + +/** + * This factory encapsulates the construction and assembly of a {@link FlowExecutor}, including the provision of its + * {@link FlowExecutionRepository} strategy. As a FactoryBean, this class has been designed for use as a + * Spring managed bean. + *

+ * The definition locator property is required, all other properties are optional. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +class FlowExecutorFactoryBean implements FactoryBean, BeanClassLoaderAware, InitializingBean { + + private static final String ALWAYS_REDIRECT_ON_PAUSE = "alwaysRedirectOnPause"; + + private static final String REDIRECT_IN_SAME_STATE = "redirectInSameState"; + + private FlowDefinitionLocator flowDefinitionLocator; + + private Integer maxFlowExecutions; + + private Integer maxFlowExecutionSnapshots; + + private Set flowExecutionAttributes; + + private FlowExecutionListenerLoader flowExecutionListenerLoader; + + private ConversationManager conversationManager; + + private ConversionService conversionService; + + private FlowExecutor flowExecutor; + + private ClassLoader classLoader; + + /** + * Sets the flow definition locator that will locate flow definitions needed for execution. Typically also a + * {@link FlowDefinitionRegistry}. Required. + * @param flowDefinitionLocator the flow definition locator (registry) + */ + public void setFlowDefinitionLocator(FlowDefinitionLocator flowDefinitionLocator) { + this.flowDefinitionLocator = flowDefinitionLocator; + } + + /** + * Set the maximum number of allowed flow executions allowed per user. + */ + public void setMaxFlowExecutions(int maxFlowExecutions) { + this.maxFlowExecutions = maxFlowExecutions; + } + + /** + * Set the maximum number of history snapshots allowed per flow execution. + */ + public void setMaxFlowExecutionSnapshots(int maxFlowExecutionSnapshots) { + this.maxFlowExecutionSnapshots = maxFlowExecutionSnapshots; + } + + /** + * Sets the system attributes that apply to flow executions launched by the executor created by this factory. + * Execution attributes may affect flow execution behavior. + * @param flowExecutionAttributes the flow execution system attributes + */ + public void setFlowExecutionAttributes(Set flowExecutionAttributes) { + this.flowExecutionAttributes = flowExecutionAttributes; + } + + /** + * Sets the strategy for loading the listeners that will observe executions of a flow definition. Allows full + * control over what listeners should apply to executions of a flow definition launched by the executor created by + * this factory. + */ + public void setFlowExecutionListenerLoader(FlowExecutionListenerLoader flowExecutionListenerLoader) { + this.flowExecutionListenerLoader = flowExecutionListenerLoader; + } + + /** + * Sets the service type that manages conversations and effectively controls how state is stored physically when a + * flow execution is paused. + */ + public void setConversationManager(ConversationManager conversationManager) { + this.conversationManager = conversationManager; + } + + // implement BeanClassLoaderAware + + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + // implementing InitializingBean + + public void afterPropertiesSet() throws Exception { + Assert.notNull(flowDefinitionLocator, "The flow definition locator property is required"); + if (conversionService == null) { + conversionService = new DefaultConversionService(); + } + MutableAttributeMap executionAttributes = createFlowExecutionAttributes(); + FlowExecutionImplFactory executionFactory = createFlowExecutionFactory(executionAttributes); + DefaultFlowExecutionRepository executionRepository = createFlowExecutionRepository(executionFactory); + executionFactory.setExecutionKeyFactory(executionRepository); + flowExecutor = new FlowExecutorImpl(flowDefinitionLocator, executionFactory, executionRepository); + } + + // implementing FactoryBean + + public Class getObjectType() { + return FlowExecutor.class; + } + + public boolean isSingleton() { + return true; + } + + public FlowExecutor getObject() throws Exception { + return flowExecutor; + } + + private MutableAttributeMap createFlowExecutionAttributes() { + LocalAttributeMap executionAttributes = new LocalAttributeMap<>(); + if (flowExecutionAttributes != null) { + for (FlowElementAttribute attribute : flowExecutionAttributes) { + executionAttributes.put(attribute.getName(), getConvertedValue(attribute)); + } + } + putDefaultFlowExecutionAttributes(executionAttributes); + return executionAttributes; + } + + private void putDefaultFlowExecutionAttributes(LocalAttributeMap executionAttributes) { + if (!executionAttributes.contains(ALWAYS_REDIRECT_ON_PAUSE)) { + executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, true); + } + if (!executionAttributes.contains(REDIRECT_IN_SAME_STATE)) { + executionAttributes.put(REDIRECT_IN_SAME_STATE, true); + } + } + + private DefaultFlowExecutionRepository createFlowExecutionRepository(FlowExecutionFactory executionFactory) { + ConversationManager conversationManager = createConversationManager(); + FlowExecutionSnapshotFactory snapshotFactory = createFlowExecutionSnapshotFactory(executionFactory); + DefaultFlowExecutionRepository rep = new DefaultFlowExecutionRepository(conversationManager, snapshotFactory); + if (maxFlowExecutionSnapshots != null) { + rep.setMaxSnapshots(maxFlowExecutionSnapshots); + } + return rep; + } + + private ConversationManager createConversationManager() { + if (conversationManager == null) { + conversationManager = new SessionBindingConversationManager(); + if (maxFlowExecutions != null) { + ((SessionBindingConversationManager) conversationManager).setMaxConversations(maxFlowExecutions); + } + } + return this.conversationManager; + } + + private FlowExecutionSnapshotFactory createFlowExecutionSnapshotFactory(FlowExecutionFactory executionFactory) { + if (maxFlowExecutionSnapshots != null && maxFlowExecutionSnapshots == 0) { + maxFlowExecutionSnapshots = 1; + return new SimpleFlowExecutionSnapshotFactory(executionFactory, flowDefinitionLocator); + } else { + return new SerializedFlowExecutionSnapshotFactory(executionFactory, flowDefinitionLocator); + } + } + + private FlowExecutionImplFactory createFlowExecutionFactory(AttributeMap executionAttributes) { + FlowExecutionImplFactory executionFactory = new FlowExecutionImplFactory(); + executionFactory.setExecutionAttributes(executionAttributes); + if (flowExecutionListenerLoader != null) { + executionFactory.setExecutionListenerLoader(flowExecutionListenerLoader); + } + return executionFactory; + } + + // utility methods + + private Object getConvertedValue(FlowElementAttribute attribute) { + if (attribute.needsTypeConversion()) { + Class targetType = fromStringToClass(attribute.getType()); + ConversionExecutor converter = conversionService.getConversionExecutor(String.class, targetType); + return converter.execute(attribute.getValue()); + } else { + return attribute.getValue(); + } + } + + private Class fromStringToClass(String name) { + Class clazz = conversionService.getClassForAlias(name); + if (clazz != null) { + return clazz; + } else { + try { + return ClassUtils.forName(name, classLoader); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Unable to load class '" + name + "'"); + } + } + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/config/WebFlowConfigNamespaceHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/config/WebFlowConfigNamespaceHandler.java index 064f188d..026a6344 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/config/WebFlowConfigNamespaceHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/config/WebFlowConfigNamespaceHandler.java @@ -1,34 +1,34 @@ -/* - * 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 - * - * https://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.config; - -import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - -/** - * NamespaceHandler for the webflow-config namespace. - * - * @author Keith Donald - * @author Ben Hale - * @author Jeremy Grelle - */ -public class WebFlowConfigNamespaceHandler extends NamespaceHandlerSupport { - public void init() { - registerBeanDefinitionParser("flow-executor", new FlowExecutorBeanDefinitionParser()); - registerBeanDefinitionParser("flow-execution-listeners", new FlowExecutionListenerLoaderBeanDefinitionParser()); - registerBeanDefinitionParser("flow-registry", new FlowRegistryBeanDefinitionParser()); - registerBeanDefinitionParser("flow-builder-services", new FlowBuilderServicesBeanDefinitionParser()); - } +/* + * 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 + * + * https://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.config; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +/** + * NamespaceHandler for the webflow-config namespace. + * + * @author Keith Donald + * @author Ben Hale + * @author Jeremy Grelle + */ +public class WebFlowConfigNamespaceHandler extends NamespaceHandlerSupport { + public void init() { + registerBeanDefinitionParser("flow-executor", new FlowExecutorBeanDefinitionParser()); + registerBeanDefinitionParser("flow-execution-listeners", new FlowExecutionListenerLoaderBeanDefinitionParser()); + registerBeanDefinitionParser("flow-registry", new FlowRegistryBeanDefinitionParser()); + registerBeanDefinitionParser("flow-builder-services", new FlowBuilderServicesBeanDefinitionParser()); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContext.java b/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContext.java index 507cab2e..5ed7db56 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContext.java @@ -1,216 +1,216 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.context; - -import java.io.Writer; -import java.security.Principal; -import java.util.Locale; - -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.core.collection.ParameterMap; -import org.springframework.webflow.core.collection.SharedAttributeMap; - -/** - * A facade that provides normalized access to an external system that has called into the Spring Web Flow system. - *

- * This context object provides a normalized interface for internal web flow artifacts to use to reason on and - * manipulate the state of an external actor calling into SWF to execute flows. It represents the context about a - * single, external client request to manipulate a flow execution. - *

- * The design of this interface was inspired by JSF's own ExternalContext abstraction and shares the same name for - * consistency. If a particular external client type does not support all methods defined by this interface, they can - * just be implemented as returning an empty map or null. - * - * @author Keith Donald - * @author Erwin Vervaet - * @author Jeremy Grelle - * @author Scott Andrews - */ -public interface ExternalContext { - - /** - * Returns the logical path to the application hosting this external context. - * @return the context path - */ - String getContextPath(); - - /** - * Provides access to the parameters associated with the user request that led to SWF being called. This map is - * expected to be immutable and cannot be changed. - * @return the immutable request parameter map - */ - ParameterMap getRequestParameterMap(); - - /** - * Provides access to the external request attribute map, providing a storage for data local to the current user - * request and accessible to both internal and external SWF artifacts. - * @return the mutable request attribute map - */ - MutableAttributeMap getRequestMap(); - - /** - * Provides access to the external session map, providing a storage for data local to the current user session and - * accessible to both internal and external SWF artifacts. - * @return the mutable session attribute map - */ - SharedAttributeMap getSessionMap(); - - /** - * Provides access to the global external session map, providing a storage for data globally accross the user - * session and accessible to both internal and external SWF artifacts. - *

- * Note: most external context implementations do not distinguish between the concept of a "local" user session - * scope and a "global" session scope. Otherwise this method returns the same map as calling {@link #getSessionMap()}. - * @return the mutable global session attribute map - */ - SharedAttributeMap getGlobalSessionMap(); - - /** - * Provides access to the external application map, providing a storage for data local to the current user - * application and accessible to both internal and external SWF artifacts. - * @return the mutable application attribute map - */ - SharedAttributeMap getApplicationMap(); - - /** - * Returns true if the current request is an asynchronous Ajax request. - * @return true if the current request is an Ajax request - */ - boolean isAjaxRequest(); - - /** - * Get a flow execution URL for the execution with the provided key. Typically used by response writers that write - * out references to the flow execution to support postback on a subsequent request. The URL returned is encoded. - * @param flowId the flow definition id - * @param flowExecutionKey the flow execution key - * @return the flow execution URL - */ - String getFlowExecutionUrl(String flowId, String flowExecutionKey); - - /** - * Provides access to the user's principal security object. - * @return the user principal - */ - Principal getCurrentUser(); - - /** - * Returns the client locale. - * @return the locale - */ - Locale getLocale(); - - /** - * Provides access to the context object for the current environment. - * @return the environment specific context object - */ - Object getNativeContext(); - - /** - * Provides access to the request object for the current environment. - * @return the environment specific request object. - */ - Object getNativeRequest(); - - /** - * Provides access to the response object for the current environment. - * @return the environment specific response object. - */ - Object getNativeResponse(); - - /** - * Get a writer for writing out a response. - * @return the writer - * @throws IllegalStateException if the response has completed or is not allowed - */ - Writer getResponseWriter() throws IllegalStateException; - - /** - * Is a render response allowed to be written for this request? Always return false after a response has been - * completed. May return false before that to indicate a response is not allowed to be completed. - * @return true if yes, false otherwise - */ - boolean isResponseAllowed(); - - /** - * Request that a flow execution redirect be performed by the calling environment. Typically called from within a - * flow execution to request a refresh operation, usually to support "refresh after event processing" behavior. - * Calling this method also sets responseComplete status to true. - * @see #isResponseComplete() - * @throws IllegalStateException if the response has completed - */ - void requestFlowExecutionRedirect() throws IllegalStateException; - - /** - * Request that a flow definition redirect be performed by the calling environment. Typically called from within a - * flow execution end state to request starting a new, independent execution of a flow in a chain-like manner. - * Calling this method also sets responseComplete status to true. - * @see #isResponseComplete() - * @param flowId the id of the flow definition to redirect to - * @param input input to pass the flow; this input is generally encoded the url to launch the flow - * @throws IllegalStateException if the response has completed - */ - void requestFlowDefinitionRedirect(String flowId, MutableAttributeMap input) throws IllegalStateException; - - /** - * Request a redirect to an arbitrary resource location. May not be supported in some environments. Calling this - * method also sets responseComplete status to true. - * @see #isResponseComplete() - * @param location the location of the resource to redirect to - * @throws IllegalStateException if the response has completed - */ - void requestExternalRedirect(String location) throws IllegalStateException; - - /** - * Request that the current redirect requested be sent to the client in a manner that causes the client to issue the - * redirect from a popup dialog. Only call this method after a redirect has been requested. - * @see #requestFlowExecutionRedirect() - * @see #requestFlowDefinitionRedirect(String, MutableAttributeMap) - * @see #requestExternalRedirect(String) - * @throws IllegalStateException if a redirect has not been requested - */ - void requestRedirectInPopup() throws IllegalStateException; - - /** - * Called by flow artifacts such as View states and end states to indicate they handled the response, typically by - * writing out content to the response stream. Setting this flag allows this external context to know the response - * was handled, and that it not need to take additional response handling action itself. - */ - void recordResponseComplete(); - - /** - * Has the response been completed? Response complete status can be achieved by: - *
    - *
  • Writing out the response and calling {@link #recordResponseComplete()}, or - *
  • Calling one of the redirect request methods - *
- * @see #getResponseWriter() - * @see #recordResponseComplete() - * @see #requestFlowExecutionRedirect() - * @see #requestFlowDefinitionRedirect(String, MutableAttributeMap) - * @see #requestExternalRedirect(String) - * @return true if yes, false otherwise - */ - boolean isResponseComplete(); - - /** - * Returns true if the response has been completed with flow execution redirect request. - * @return true if a redirect response has been completed - * @see #isResponseComplete() - * @see #requestFlowExecutionRedirect() - */ - boolean isResponseCompleteFlowExecutionRedirect(); - -} +/* + * Copyright 2004-2012 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 + * + * https://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.context; + +import java.io.Writer; +import java.security.Principal; +import java.util.Locale; + +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.core.collection.ParameterMap; +import org.springframework.webflow.core.collection.SharedAttributeMap; + +/** + * A facade that provides normalized access to an external system that has called into the Spring Web Flow system. + *

+ * This context object provides a normalized interface for internal web flow artifacts to use to reason on and + * manipulate the state of an external actor calling into SWF to execute flows. It represents the context about a + * single, external client request to manipulate a flow execution. + *

+ * The design of this interface was inspired by JSF's own ExternalContext abstraction and shares the same name for + * consistency. If a particular external client type does not support all methods defined by this interface, they can + * just be implemented as returning an empty map or null. + * + * @author Keith Donald + * @author Erwin Vervaet + * @author Jeremy Grelle + * @author Scott Andrews + */ +public interface ExternalContext { + + /** + * Returns the logical path to the application hosting this external context. + * @return the context path + */ + String getContextPath(); + + /** + * Provides access to the parameters associated with the user request that led to SWF being called. This map is + * expected to be immutable and cannot be changed. + * @return the immutable request parameter map + */ + ParameterMap getRequestParameterMap(); + + /** + * Provides access to the external request attribute map, providing a storage for data local to the current user + * request and accessible to both internal and external SWF artifacts. + * @return the mutable request attribute map + */ + MutableAttributeMap getRequestMap(); + + /** + * Provides access to the external session map, providing a storage for data local to the current user session and + * accessible to both internal and external SWF artifacts. + * @return the mutable session attribute map + */ + SharedAttributeMap getSessionMap(); + + /** + * Provides access to the global external session map, providing a storage for data globally accross the user + * session and accessible to both internal and external SWF artifacts. + *

+ * Note: most external context implementations do not distinguish between the concept of a "local" user session + * scope and a "global" session scope. Otherwise this method returns the same map as calling {@link #getSessionMap()}. + * @return the mutable global session attribute map + */ + SharedAttributeMap getGlobalSessionMap(); + + /** + * Provides access to the external application map, providing a storage for data local to the current user + * application and accessible to both internal and external SWF artifacts. + * @return the mutable application attribute map + */ + SharedAttributeMap getApplicationMap(); + + /** + * Returns true if the current request is an asynchronous Ajax request. + * @return true if the current request is an Ajax request + */ + boolean isAjaxRequest(); + + /** + * Get a flow execution URL for the execution with the provided key. Typically used by response writers that write + * out references to the flow execution to support postback on a subsequent request. The URL returned is encoded. + * @param flowId the flow definition id + * @param flowExecutionKey the flow execution key + * @return the flow execution URL + */ + String getFlowExecutionUrl(String flowId, String flowExecutionKey); + + /** + * Provides access to the user's principal security object. + * @return the user principal + */ + Principal getCurrentUser(); + + /** + * Returns the client locale. + * @return the locale + */ + Locale getLocale(); + + /** + * Provides access to the context object for the current environment. + * @return the environment specific context object + */ + Object getNativeContext(); + + /** + * Provides access to the request object for the current environment. + * @return the environment specific request object. + */ + Object getNativeRequest(); + + /** + * Provides access to the response object for the current environment. + * @return the environment specific response object. + */ + Object getNativeResponse(); + + /** + * Get a writer for writing out a response. + * @return the writer + * @throws IllegalStateException if the response has completed or is not allowed + */ + Writer getResponseWriter() throws IllegalStateException; + + /** + * Is a render response allowed to be written for this request? Always return false after a response has been + * completed. May return false before that to indicate a response is not allowed to be completed. + * @return true if yes, false otherwise + */ + boolean isResponseAllowed(); + + /** + * Request that a flow execution redirect be performed by the calling environment. Typically called from within a + * flow execution to request a refresh operation, usually to support "refresh after event processing" behavior. + * Calling this method also sets responseComplete status to true. + * @see #isResponseComplete() + * @throws IllegalStateException if the response has completed + */ + void requestFlowExecutionRedirect() throws IllegalStateException; + + /** + * Request that a flow definition redirect be performed by the calling environment. Typically called from within a + * flow execution end state to request starting a new, independent execution of a flow in a chain-like manner. + * Calling this method also sets responseComplete status to true. + * @see #isResponseComplete() + * @param flowId the id of the flow definition to redirect to + * @param input input to pass the flow; this input is generally encoded the url to launch the flow + * @throws IllegalStateException if the response has completed + */ + void requestFlowDefinitionRedirect(String flowId, MutableAttributeMap input) throws IllegalStateException; + + /** + * Request a redirect to an arbitrary resource location. May not be supported in some environments. Calling this + * method also sets responseComplete status to true. + * @see #isResponseComplete() + * @param location the location of the resource to redirect to + * @throws IllegalStateException if the response has completed + */ + void requestExternalRedirect(String location) throws IllegalStateException; + + /** + * Request that the current redirect requested be sent to the client in a manner that causes the client to issue the + * redirect from a popup dialog. Only call this method after a redirect has been requested. + * @see #requestFlowExecutionRedirect() + * @see #requestFlowDefinitionRedirect(String, MutableAttributeMap) + * @see #requestExternalRedirect(String) + * @throws IllegalStateException if a redirect has not been requested + */ + void requestRedirectInPopup() throws IllegalStateException; + + /** + * Called by flow artifacts such as View states and end states to indicate they handled the response, typically by + * writing out content to the response stream. Setting this flag allows this external context to know the response + * was handled, and that it not need to take additional response handling action itself. + */ + void recordResponseComplete(); + + /** + * Has the response been completed? Response complete status can be achieved by: + *
    + *
  • Writing out the response and calling {@link #recordResponseComplete()}, or + *
  • Calling one of the redirect request methods + *
+ * @see #getResponseWriter() + * @see #recordResponseComplete() + * @see #requestFlowExecutionRedirect() + * @see #requestFlowDefinitionRedirect(String, MutableAttributeMap) + * @see #requestExternalRedirect(String) + * @return true if yes, false otherwise + */ + boolean isResponseComplete(); + + /** + * Returns true if the response has been completed with flow execution redirect request. + * @return true if a redirect response has been completed + * @see #isResponseComplete() + * @see #requestFlowExecutionRedirect() + */ + boolean isResponseCompleteFlowExecutionRedirect(); + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContextHolder.java b/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContextHolder.java index 2bb55a95..3093b965 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContextHolder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/ExternalContextHolder.java @@ -1,56 +1,56 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.context; - -import org.springframework.core.NamedThreadLocal; - -/** - * Simple holder class that associates an {@link ExternalContext} instance with the current thread. The ExternalContext - * will not be inherited by any child threads spawned by the current thread. - *

- * Used as a central holder for the current ExternalContext in Spring Web Flow, wherever necessary. Often used by - * artifacts needing access to the current application session. - * - * @see ExternalContext - * - * @author Keith Donald - */ -public final class ExternalContextHolder { - - private static final ThreadLocal externalContextHolder = new NamedThreadLocal<>( - "Flow ExternalContext"); - - /** - * Associate the given ExternalContext with the current thread. - * @param externalContext the current ExternalContext, or null to reset the thread-bound context - */ - public static void setExternalContext(ExternalContext externalContext) { - externalContextHolder.set(externalContext); - } - - /** - * Return the ExternalContext associated with the current thread, if any. - * @return the current ExternalContext - */ - public static ExternalContext getExternalContext() { - return externalContextHolder.get(); - } - - // not instantiable - private ExternalContextHolder() { - } - -} +/* + * Copyright 2004-2012 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 + * + * https://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.context; + +import org.springframework.core.NamedThreadLocal; + +/** + * Simple holder class that associates an {@link ExternalContext} instance with the current thread. The ExternalContext + * will not be inherited by any child threads spawned by the current thread. + *

+ * Used as a central holder for the current ExternalContext in Spring Web Flow, wherever necessary. Often used by + * artifacts needing access to the current application session. + * + * @see ExternalContext + * + * @author Keith Donald + */ +public final class ExternalContextHolder { + + private static final ThreadLocal externalContextHolder = new NamedThreadLocal<>( + "Flow ExternalContext"); + + /** + * Associate the given ExternalContext with the current thread. + * @param externalContext the current ExternalContext, or null to reset the thread-bound context + */ + public static void setExternalContext(ExternalContext externalContext) { + externalContextHolder.set(externalContext); + } + + /** + * Return the ExternalContext associated with the current thread, if any. + * @return the current ExternalContext + */ + public static ExternalContext getExternalContext() { + return externalContextHolder.get(); + } + + // not instantiable + private ExternalContextHolder() { + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/context/web/HttpSessionMapBindingListener.java b/spring-webflow/src/main/java/org/springframework/webflow/context/web/HttpSessionMapBindingListener.java index 84cd1379..68d5681a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/context/web/HttpSessionMapBindingListener.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/context/web/HttpSessionMapBindingListener.java @@ -1,77 +1,77 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.context.web; - -import java.util.Map; - -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; - -import org.springframework.webflow.core.collection.AttributeMapBindingEvent; -import org.springframework.webflow.core.collection.AttributeMapBindingListener; -import org.springframework.webflow.core.collection.LocalAttributeMap; - -/** - * Helper class that adapts a generic {@link AttributeMapBindingListener} to a HTTP specific - * {@link HttpSessionBindingListener}. Calls will be forwarded to the wrapped listener. - * - * @author Keith Donald - */ -public class HttpSessionMapBindingListener implements HttpSessionBindingListener { - - private AttributeMapBindingListener listener; - - private Map sessionMap; - - /** - * Create a new wrapper for given listener. - * @param listener the listener to wrap - * @param sessionMap the session map containing the listener - */ - public HttpSessionMapBindingListener(AttributeMapBindingListener listener, Map sessionMap) { - this.listener = listener; - this.sessionMap = sessionMap; - } - - /** - * Returns the wrapped listener. - */ - public AttributeMapBindingListener getListener() { - return listener; - } - - /** - * Returns the session map containing the listener. - */ - public Map getSessionMap() { - return sessionMap; - } - - public void valueBound(HttpSessionBindingEvent event) { - listener.valueBound(getContextBindingEvent(event)); - } - - public void valueUnbound(HttpSessionBindingEvent event) { - listener.valueUnbound(getContextBindingEvent(event)); - } - - /** - * Create a attribute map binding event for given HTTP session binding event. - */ - private AttributeMapBindingEvent getContextBindingEvent(HttpSessionBindingEvent event) { - return new AttributeMapBindingEvent(new LocalAttributeMap<>(sessionMap), event.getName(), listener); - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.context.web; + +import java.util.Map; + +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; + +import org.springframework.webflow.core.collection.AttributeMapBindingEvent; +import org.springframework.webflow.core.collection.AttributeMapBindingListener; +import org.springframework.webflow.core.collection.LocalAttributeMap; + +/** + * Helper class that adapts a generic {@link AttributeMapBindingListener} to a HTTP specific + * {@link HttpSessionBindingListener}. Calls will be forwarded to the wrapped listener. + * + * @author Keith Donald + */ +public class HttpSessionMapBindingListener implements HttpSessionBindingListener { + + private AttributeMapBindingListener listener; + + private Map sessionMap; + + /** + * Create a new wrapper for given listener. + * @param listener the listener to wrap + * @param sessionMap the session map containing the listener + */ + public HttpSessionMapBindingListener(AttributeMapBindingListener listener, Map sessionMap) { + this.listener = listener; + this.sessionMap = sessionMap; + } + + /** + * Returns the wrapped listener. + */ + public AttributeMapBindingListener getListener() { + return listener; + } + + /** + * Returns the session map containing the listener. + */ + public Map getSessionMap() { + return sessionMap; + } + + public void valueBound(HttpSessionBindingEvent event) { + listener.valueBound(getContextBindingEvent(event)); + } + + public void valueUnbound(HttpSessionBindingEvent event) { + listener.valueUnbound(getContextBindingEvent(event)); + } + + /** + * Create a attribute map binding event for given HTTP session binding event. + */ + private AttributeMapBindingEvent getContextBindingEvent(HttpSessionBindingEvent event) { + return new AttributeMapBindingEvent(new LocalAttributeMap<>(sessionMap), event.getName(), listener); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/conversation/Conversation.java b/spring-webflow/src/main/java/org/springframework/webflow/conversation/Conversation.java index c6ca7140..af95a2e0 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/conversation/Conversation.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/conversation/Conversation.java @@ -1,97 +1,97 @@ -/* - * 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 - * - * https://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.conversation; - -/** - * A service interface for working with state associated with a single logical user interaction called a "conversation" - * in the scope of a single request. Conversation objects are not thread safe and should not be shared among multiple - * threads. - *

- * A conversation provides a "task" context that is begun and eventually ends. Between the beginning and the end - * attributes can be placed in and read from a conversation's context. - *

- * A conversation needs to be {@link #lock() locked} to obtain exclusive access to it before it can be manipulated. Once - * manipulation is finished, you need to {@link #unlock() unlock} the conversation. So code interacting with a - * conversation always looks like this: - * - *

- * Conversation conv = ...;
- * conv.lock();
- * try {
- *    // work with the Conversation object, calling methods like
- *    // getAttribute(), putAttribute() and end()
- * }
- * finally {
- *    conv.unlock();
- * }
- * 
- * - *

- * Note that the attributes associated with a conversation are not "conversation scope" as defined for a flow execution. - * They can be any attributes, possibly technical in nature, associated with the conversation. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface Conversation { - - /** - * Returns the unique id assigned to this conversation. This id remains the same throughout the life of the - * conversation. This method can be safely called without owning the lock of this conversation. - * @return the conversation id - */ - ConversationId getId(); - - /** - * Lock this conversation. May block until the lock is available, if someone else has acquired the lock. - * @throws ConversationLockException if the lock could not be acquired - */ - void lock() throws ConversationLockException; - - /** - * Returns the conversation attribute with the specified name. You need to acquire the lock on this conversation - * before calling this method. - * @param name the attribute name - * @return the attribute value - */ - Object getAttribute(Object name); - - /** - * Puts a conversation attribute into this context. You need to acquire the lock on this conversation before calling - * this method. - * @param name the attribute name - * @param value the attribute value - */ - void putAttribute(Object name, Object value); - - /** - * Removes a conversation attribute. You need to acquire the lock on this conversation before calling this method. - * @param name the attribute name - */ - void removeAttribute(Object name); - - /** - * Ends this conversation. This method should only be called once to terminate the conversation and cleanup any - * allocated resources. You need to aquire the lock on this conversation before calling this method. - */ - void end(); - - /** - * Unlock this conversation, making it available to others for manipulation. - */ - void unlock(); - +/* + * 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 + * + * https://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.conversation; + +/** + * A service interface for working with state associated with a single logical user interaction called a "conversation" + * in the scope of a single request. Conversation objects are not thread safe and should not be shared among multiple + * threads. + *

+ * A conversation provides a "task" context that is begun and eventually ends. Between the beginning and the end + * attributes can be placed in and read from a conversation's context. + *

+ * A conversation needs to be {@link #lock() locked} to obtain exclusive access to it before it can be manipulated. Once + * manipulation is finished, you need to {@link #unlock() unlock} the conversation. So code interacting with a + * conversation always looks like this: + * + *

+ * Conversation conv = ...;
+ * conv.lock();
+ * try {
+ *    // work with the Conversation object, calling methods like
+ *    // getAttribute(), putAttribute() and end()
+ * }
+ * finally {
+ *    conv.unlock();
+ * }
+ * 
+ * + *

+ * Note that the attributes associated with a conversation are not "conversation scope" as defined for a flow execution. + * They can be any attributes, possibly technical in nature, associated with the conversation. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface Conversation { + + /** + * Returns the unique id assigned to this conversation. This id remains the same throughout the life of the + * conversation. This method can be safely called without owning the lock of this conversation. + * @return the conversation id + */ + ConversationId getId(); + + /** + * Lock this conversation. May block until the lock is available, if someone else has acquired the lock. + * @throws ConversationLockException if the lock could not be acquired + */ + void lock() throws ConversationLockException; + + /** + * Returns the conversation attribute with the specified name. You need to acquire the lock on this conversation + * before calling this method. + * @param name the attribute name + * @return the attribute value + */ + Object getAttribute(Object name); + + /** + * Puts a conversation attribute into this context. You need to acquire the lock on this conversation before calling + * this method. + * @param name the attribute name + * @param value the attribute value + */ + void putAttribute(Object name, Object value); + + /** + * Removes a conversation attribute. You need to acquire the lock on this conversation before calling this method. + * @param name the attribute name + */ + void removeAttribute(Object name); + + /** + * Ends this conversation. This method should only be called once to terminate the conversation and cleanup any + * allocated resources. You need to aquire the lock on this conversation before calling this method. + */ + void end(); + + /** + * Unlock this conversation, making it available to others for manipulation. + */ + void unlock(); + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/conversation/ConversationException.java b/spring-webflow/src/main/java/org/springframework/webflow/conversation/ConversationException.java index b8255f02..3cdb720c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/conversation/ConversationException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/conversation/ConversationException.java @@ -1,41 +1,41 @@ -/* - * 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 - * - * https://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.conversation; - -/** - * The root of the conversation service exception hierarchy. - * - * @author Keith Donald - */ -public abstract class ConversationException extends RuntimeException { - - /** - * Creates a conversation service exception. - * @param message a descriptive message - */ - public ConversationException(String message) { - super(message); - } - - /** - * Creates a conversation service exception. - * @param message a descriptive message - * @param cause the root cause of the problem - */ - public ConversationException(String message, Throwable cause) { - super(message, cause); - } +/* + * 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 + * + * https://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.conversation; + +/** + * The root of the conversation service exception hierarchy. + * + * @author Keith Donald + */ +public abstract class ConversationException extends RuntimeException { + + /** + * Creates a conversation service exception. + * @param message a descriptive message + */ + public ConversationException(String message) { + super(message); + } + + /** + * Creates a conversation service exception. + * @param message a descriptive message + * @param cause the root cause of the problem + */ + public ConversationException(String message, Throwable cause) { + super(message, cause); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/conversation/NoSuchConversationException.java b/spring-webflow/src/main/java/org/springframework/webflow/conversation/NoSuchConversationException.java index 719d90b0..eeb069c5 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/conversation/NoSuchConversationException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/conversation/NoSuchConversationException.java @@ -1,47 +1,47 @@ -/* - * 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 - * - * https://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.conversation; - -/** - * Thrown when no logical conversation exists with the specified conversationId. This might occur if the - * conversation ended, expired, or was otherwise invalidated, but a client view still references it. - * - * @author Keith Donald - */ -public class NoSuchConversationException extends ConversationException { - - /** - * The unique conversation identifier that was invalid. - */ - private ConversationId conversationId; - - /** - * Create a new conversation lookup exception. - * @param conversationId the conversation id - */ - public NoSuchConversationException(ConversationId conversationId) { - super("No conversation could be found with id '" + conversationId - + "' -- perhaps this conversation has ended? "); - this.conversationId = conversationId; - } - - /** - * Returns the conversation id that was not found. - */ - public ConversationId getConversationId() { - return conversationId; - } +/* + * 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 + * + * https://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.conversation; + +/** + * Thrown when no logical conversation exists with the specified conversationId. This might occur if the + * conversation ended, expired, or was otherwise invalidated, but a client view still references it. + * + * @author Keith Donald + */ +public class NoSuchConversationException extends ConversationException { + + /** + * The unique conversation identifier that was invalid. + */ + private ConversationId conversationId; + + /** + * Create a new conversation lookup exception. + * @param conversationId the conversation id + */ + public NoSuchConversationException(ConversationId conversationId) { + super("No conversation could be found with id '" + conversationId + + "' -- perhaps this conversation has ended? "); + this.conversationId = conversationId; + } + + /** + * Returns the conversation id that was not found. + */ + public ConversationId getConversationId() { + return conversationId; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ContainedConversation.java b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ContainedConversation.java index b1663af2..f52982e2 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ContainedConversation.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ContainedConversation.java @@ -1,135 +1,135 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.conversation.impl; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.webflow.context.ExternalContextHolder; -import org.springframework.webflow.conversation.Conversation; -import org.springframework.webflow.conversation.ConversationId; -import org.springframework.webflow.core.collection.SharedAttributeMap; - -/** - * Internal {@link Conversation} implementation used by the conversation container. - *

- * This is an internal helper class of the {@link SessionBindingConversationManager}. - * - * @author Erwin Vervaet - */ -public class ContainedConversation implements Conversation, Serializable { - - private static final Log logger = LogFactory.getLog(SessionBindingConversationManager.class); - - private ConversationContainer container; - - private ConversationId id; - - private ConversationLock lock; - - private Map attributes; - - /** - * Create a new contained conversation. - * @param container the container containing the conversation - * @param id the unique id assigned to the conversation - * @param lock the conversation lock - */ - public ContainedConversation(ConversationContainer container, ConversationId id, ConversationLock lock) { - this.container = container; - this.id = id; - this.lock = lock; - this.attributes = new HashMap<>(); - } - - protected void setContainer(ConversationContainer container) { - this.container = container; - } - - public ConversationId getId() { - return this.id; - } - - protected void setId(ConversationId id) { - this.id = id; - } - - public void lock() { - if (logger.isDebugEnabled()) { - logger.debug("Locking conversation " + this.id); - } - this.lock.lock(); - } - - public Object getAttribute(Object name) { - return this.attributes.get(name); - } - - public void putAttribute(Object name, Object value) { - if (logger.isDebugEnabled()) { - logger.debug("Putting conversation attribute '" + name + "' with value " + value); - } - this.attributes.put(name, value); - } - - public void removeAttribute(Object name) { - if (logger.isDebugEnabled()) { - logger.debug("Removing conversation attribute '" + name + "'"); - } - this.attributes.remove(name); - } - - public void end() { - if (logger.isDebugEnabled()) { - logger.debug("Ending conversation " + this.id); - } - this.container.removeConversation(getId()); - } - - public void unlock() { - if (logger.isDebugEnabled()) { - logger.debug("Unlocking conversation " + this.id); - } - this.lock.unlock(); - // re-bind the conversation container in the session - // this is required to make session replication work correctly in - // a clustered environment - // we do this after releasing the lock since we're no longer - // manipulating the contents of the conversation - SharedAttributeMap sessionMap = ExternalContextHolder.getExternalContext().getSessionMap(); - synchronized (sessionMap.getMutex()) { - sessionMap.put(this.container.getSessionKey(), this.container); - } - } - - public String toString() { - return getId().toString(); - } - - // id based equality - - public boolean equals(Object obj) { - return obj instanceof ContainedConversation && this.id.equals(((ContainedConversation) obj).id); - } - - public int hashCode() { - return this.id.hashCode(); - } - -} +/* + * Copyright 2004-2012 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 + * + * https://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.conversation.impl; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.webflow.context.ExternalContextHolder; +import org.springframework.webflow.conversation.Conversation; +import org.springframework.webflow.conversation.ConversationId; +import org.springframework.webflow.core.collection.SharedAttributeMap; + +/** + * Internal {@link Conversation} implementation used by the conversation container. + *

+ * This is an internal helper class of the {@link SessionBindingConversationManager}. + * + * @author Erwin Vervaet + */ +public class ContainedConversation implements Conversation, Serializable { + + private static final Log logger = LogFactory.getLog(SessionBindingConversationManager.class); + + private ConversationContainer container; + + private ConversationId id; + + private ConversationLock lock; + + private Map attributes; + + /** + * Create a new contained conversation. + * @param container the container containing the conversation + * @param id the unique id assigned to the conversation + * @param lock the conversation lock + */ + public ContainedConversation(ConversationContainer container, ConversationId id, ConversationLock lock) { + this.container = container; + this.id = id; + this.lock = lock; + this.attributes = new HashMap<>(); + } + + protected void setContainer(ConversationContainer container) { + this.container = container; + } + + public ConversationId getId() { + return this.id; + } + + protected void setId(ConversationId id) { + this.id = id; + } + + public void lock() { + if (logger.isDebugEnabled()) { + logger.debug("Locking conversation " + this.id); + } + this.lock.lock(); + } + + public Object getAttribute(Object name) { + return this.attributes.get(name); + } + + public void putAttribute(Object name, Object value) { + if (logger.isDebugEnabled()) { + logger.debug("Putting conversation attribute '" + name + "' with value " + value); + } + this.attributes.put(name, value); + } + + public void removeAttribute(Object name) { + if (logger.isDebugEnabled()) { + logger.debug("Removing conversation attribute '" + name + "'"); + } + this.attributes.remove(name); + } + + public void end() { + if (logger.isDebugEnabled()) { + logger.debug("Ending conversation " + this.id); + } + this.container.removeConversation(getId()); + } + + public void unlock() { + if (logger.isDebugEnabled()) { + logger.debug("Unlocking conversation " + this.id); + } + this.lock.unlock(); + // re-bind the conversation container in the session + // this is required to make session replication work correctly in + // a clustered environment + // we do this after releasing the lock since we're no longer + // manipulating the contents of the conversation + SharedAttributeMap sessionMap = ExternalContextHolder.getExternalContext().getSessionMap(); + synchronized (sessionMap.getMutex()) { + sessionMap.put(this.container.getSessionKey(), this.container); + } + } + + public String toString() { + return getId().toString(); + } + + // id based equality + + public boolean equals(Object obj) { + return obj instanceof ContainedConversation && this.id.equals(((ContainedConversation) obj).id); + } + + public int hashCode() { + return this.id.hashCode(); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ConversationLock.java b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ConversationLock.java index 534d3a6c..dcd10e83 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ConversationLock.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/ConversationLock.java @@ -1,39 +1,39 @@ -/* - * 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 - * - * https://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.conversation.impl; - -import java.io.Serializable; - -import org.springframework.webflow.conversation.ConversationLockException; - -/** - * A normalized interface for conversation locks, used to obtain exclusive access to a conversation. - * - * @author Keith Donald - */ -public interface ConversationLock extends Serializable { - - /** - * Acquire the conversation lock. - * @throws ConversationLockException if an exception is thrown attempting to acquire this lock - */ - void lock() throws ConversationLockException; - - /** - * Release the conversation lock. - */ - void unlock(); +/* + * 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 + * + * https://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.conversation.impl; + +import java.io.Serializable; + +import org.springframework.webflow.conversation.ConversationLockException; + +/** + * A normalized interface for conversation locks, used to obtain exclusive access to a conversation. + * + * @author Keith Donald + */ +public interface ConversationLock extends Serializable { + + /** + * Acquire the conversation lock. + * @throws ConversationLockException if an exception is thrown attempting to acquire this lock + */ + void lock() throws ConversationLockException; + + /** + * Release the conversation lock. + */ + void unlock(); } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/JdkConcurrentConversationLock.java b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/JdkConcurrentConversationLock.java index f9111b2f..023bd4f8 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/JdkConcurrentConversationLock.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/JdkConcurrentConversationLock.java @@ -1,54 +1,54 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.conversation.impl; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.springframework.webflow.conversation.ConversationLockException; - -/** - * A conversation lock that relies on a {@link ReentrantLock} within Java 5's util.concurrent.locks - * package. - * - * @author Keith Donald - */ -public class JdkConcurrentConversationLock implements ConversationLock { - - private Lock lock = new ReentrantLock(); - - private int timeoutSeconds; - - public JdkConcurrentConversationLock(int timeoutSeconds) { - this.timeoutSeconds = timeoutSeconds; - } - - public void lock() throws ConversationLockException { - try { - boolean acquired = this.lock.tryLock(this.timeoutSeconds, TimeUnit.SECONDS); - if (!acquired) { - throw new LockTimeoutException(this.timeoutSeconds); - } - } catch (InterruptedException e) { - throw new LockInterruptedException(e); - } - } - - public void unlock() { - this.lock.unlock(); - } +/* + * Copyright 2004-2012 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 + * + * https://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.conversation.impl; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.springframework.webflow.conversation.ConversationLockException; + +/** + * A conversation lock that relies on a {@link ReentrantLock} within Java 5's util.concurrent.locks + * package. + * + * @author Keith Donald + */ +public class JdkConcurrentConversationLock implements ConversationLock { + + private Lock lock = new ReentrantLock(); + + private int timeoutSeconds; + + public JdkConcurrentConversationLock(int timeoutSeconds) { + this.timeoutSeconds = timeoutSeconds; + } + + public void lock() throws ConversationLockException { + try { + boolean acquired = this.lock.tryLock(this.timeoutSeconds, TimeUnit.SECONDS); + if (!acquired) { + throw new LockTimeoutException(this.timeoutSeconds); + } + } catch (InterruptedException e) { + throw new LockInterruptedException(e); + } + } + + public void unlock() { + this.lock.unlock(); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/NoOpConversationLock.java b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/NoOpConversationLock.java index 7879328f..18bd8e7e 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/NoOpConversationLock.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/NoOpConversationLock.java @@ -1,51 +1,51 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.conversation.impl; - -import java.io.ObjectStreamException; - -/** - * A singleton lock that doesn't do anything. For use when conversations don't require or choose not to implement - * locking. - * - * @author Keith Donald - */ -public class NoOpConversationLock implements ConversationLock { - - /** - * The singleton instance. - */ - public static final NoOpConversationLock INSTANCE = new NoOpConversationLock(); - - /** - * Private constructor to avoid instantiation. - */ - private NoOpConversationLock() { - } - - public void lock() { - // no-op - } - - public void unlock() { - // no-op - } - - // resolve the singleton instance - private Object readResolve() throws ObjectStreamException { - return INSTANCE; - } +/* + * Copyright 2004-2012 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 + * + * https://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.conversation.impl; + +import java.io.ObjectStreamException; + +/** + * A singleton lock that doesn't do anything. For use when conversations don't require or choose not to implement + * locking. + * + * @author Keith Donald + */ +public class NoOpConversationLock implements ConversationLock { + + /** + * The singleton instance. + */ + public static final NoOpConversationLock INSTANCE = new NoOpConversationLock(); + + /** + * Private constructor to avoid instantiation. + */ + private NoOpConversationLock() { + } + + public void lock() { + // no-op + } + + public void unlock() { + // no-op + } + + // resolve the singleton instance + private Object readResolve() throws ObjectStreamException { + return INSTANCE; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/SessionBindingConversationManager.java b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/SessionBindingConversationManager.java index 00b3b5ae..5f5872d6 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/SessionBindingConversationManager.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/conversation/impl/SessionBindingConversationManager.java @@ -1,149 +1,149 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.conversation.impl; - -import org.springframework.webflow.context.ExternalContextHolder; -import org.springframework.webflow.conversation.Conversation; -import org.springframework.webflow.conversation.ConversationException; -import org.springframework.webflow.conversation.ConversationId; -import org.springframework.webflow.conversation.ConversationManager; -import org.springframework.webflow.conversation.ConversationParameters; -import org.springframework.webflow.core.collection.SharedAttributeMap; - -/** - * Simple implementation of a conversation manager that stores conversations in the session attribute map. - *

- * Using the {@link #setMaxConversations(int) maxConversations} property, you can limit the number of concurrently - * active conversations allowed in a single session. If the maximum is exceeded, the conversation manager will - * automatically end the oldest conversation. The default is 5, which should be fine for most situations. Set it to -1 - * for no limit. Setting maxConversations to 1 allows easy resource cleanup in situations where there should only be one - * active conversation per session. - * - * @author Erwin Vervaet - */ -public class SessionBindingConversationManager implements ConversationManager { - - /** - * The name of the session attribute that will hold the conversation container used by this conversation manager. - * - * To support multiple independent conversation containers in the same web application, for example, for use with - * multiple flow executors each configured with their own session-binding conversation manager, set this field's - * value to something unique. - * @see #setSessionKey(String) - */ - private String sessionKey = "webflowConversationContainer"; - - /** - * The maximum number of active conversations allowed in a session. The default is 5. This is high enough for most - * practical situations and low enough to avoid excessive resource usage or easy denial of service attacks. - */ - private int maxConversations = 5; - - /** - * The lock timeout in seconds. - */ - private int lockTimeoutSeconds = 30; - - /** - * Returns the key this conversation manager uses to store conversation data in the session. - * @return the session key - */ - public String getSessionKey() { - return sessionKey; - } - - /** - * Sets the key this conversation manager uses to store conversation data in the session. If multiple session - * binding conversation managers are used in the same web application to back independent flow executors, this value - * should be unique among them. - * @param sessionKey the session key - */ - public void setSessionKey(String sessionKey) { - this.sessionKey = sessionKey; - } - - /** - * Returns the maximum number of allowed concurrent conversations. The default is 5. - */ - public int getMaxConversations() { - return maxConversations; - } - - /** - * Set the maximum number of allowed concurrent conversations. Set to -1 for no limit. The default is 5. - */ - public void setMaxConversations(int maxConversations) { - this.maxConversations = maxConversations; - } - - /** - * Returns the time period that can elapse before a timeout occurs on an attempt to acquire a conversation lock. The - * default is 30 seconds. - */ - public int getLockTimeoutSeconds() { - return lockTimeoutSeconds; - } - - /** - * Sets the time period that can elapse before a timeout occurs on an attempt to acquire a conversation lock. The - * default is 30 seconds. - * @param lockTimeoutSeconds the timeout period in seconds - */ - public void setLockTimeoutSeconds(int lockTimeoutSeconds) { - this.lockTimeoutSeconds = lockTimeoutSeconds; - } - - // implementing conversation manager - - public Conversation beginConversation(ConversationParameters conversationParameters) throws ConversationException { - ConversationLock lock = new JdkConcurrentConversationLock(lockTimeoutSeconds); - return getConversationContainer().createConversation(conversationParameters, lock); - } - - public Conversation getConversation(ConversationId id) throws ConversationException { - return getConversationContainer().getConversation(id); - } - - public ConversationId parseConversationId(String encodedId) throws ConversationException { - try { - return new SimpleConversationId(Integer.valueOf(encodedId)); - } catch (NumberFormatException e) { - throw new BadlyFormattedConversationIdException(encodedId, e); - } - } - - // hooks for subclassing - - protected ConversationContainer createConversationContainer() { - return new ConversationContainer(maxConversations, sessionKey); - } - - /** - * Obtain the conversation container from the session. Create a new empty container and add it to the session if no - * existing container can be found. - */ - protected final ConversationContainer getConversationContainer() { - SharedAttributeMap sessionMap = ExternalContextHolder.getExternalContext().getSessionMap(); - synchronized (sessionMap.getMutex()) { - ConversationContainer container = (ConversationContainer) sessionMap.get(sessionKey); - if (container == null) { - container = createConversationContainer(); - sessionMap.put(sessionKey, container); - } - return container; - } - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.conversation.impl; + +import org.springframework.webflow.context.ExternalContextHolder; +import org.springframework.webflow.conversation.Conversation; +import org.springframework.webflow.conversation.ConversationException; +import org.springframework.webflow.conversation.ConversationId; +import org.springframework.webflow.conversation.ConversationManager; +import org.springframework.webflow.conversation.ConversationParameters; +import org.springframework.webflow.core.collection.SharedAttributeMap; + +/** + * Simple implementation of a conversation manager that stores conversations in the session attribute map. + *

+ * Using the {@link #setMaxConversations(int) maxConversations} property, you can limit the number of concurrently + * active conversations allowed in a single session. If the maximum is exceeded, the conversation manager will + * automatically end the oldest conversation. The default is 5, which should be fine for most situations. Set it to -1 + * for no limit. Setting maxConversations to 1 allows easy resource cleanup in situations where there should only be one + * active conversation per session. + * + * @author Erwin Vervaet + */ +public class SessionBindingConversationManager implements ConversationManager { + + /** + * The name of the session attribute that will hold the conversation container used by this conversation manager. + * + * To support multiple independent conversation containers in the same web application, for example, for use with + * multiple flow executors each configured with their own session-binding conversation manager, set this field's + * value to something unique. + * @see #setSessionKey(String) + */ + private String sessionKey = "webflowConversationContainer"; + + /** + * The maximum number of active conversations allowed in a session. The default is 5. This is high enough for most + * practical situations and low enough to avoid excessive resource usage or easy denial of service attacks. + */ + private int maxConversations = 5; + + /** + * The lock timeout in seconds. + */ + private int lockTimeoutSeconds = 30; + + /** + * Returns the key this conversation manager uses to store conversation data in the session. + * @return the session key + */ + public String getSessionKey() { + return sessionKey; + } + + /** + * Sets the key this conversation manager uses to store conversation data in the session. If multiple session + * binding conversation managers are used in the same web application to back independent flow executors, this value + * should be unique among them. + * @param sessionKey the session key + */ + public void setSessionKey(String sessionKey) { + this.sessionKey = sessionKey; + } + + /** + * Returns the maximum number of allowed concurrent conversations. The default is 5. + */ + public int getMaxConversations() { + return maxConversations; + } + + /** + * Set the maximum number of allowed concurrent conversations. Set to -1 for no limit. The default is 5. + */ + public void setMaxConversations(int maxConversations) { + this.maxConversations = maxConversations; + } + + /** + * Returns the time period that can elapse before a timeout occurs on an attempt to acquire a conversation lock. The + * default is 30 seconds. + */ + public int getLockTimeoutSeconds() { + return lockTimeoutSeconds; + } + + /** + * Sets the time period that can elapse before a timeout occurs on an attempt to acquire a conversation lock. The + * default is 30 seconds. + * @param lockTimeoutSeconds the timeout period in seconds + */ + public void setLockTimeoutSeconds(int lockTimeoutSeconds) { + this.lockTimeoutSeconds = lockTimeoutSeconds; + } + + // implementing conversation manager + + public Conversation beginConversation(ConversationParameters conversationParameters) throws ConversationException { + ConversationLock lock = new JdkConcurrentConversationLock(lockTimeoutSeconds); + return getConversationContainer().createConversation(conversationParameters, lock); + } + + public Conversation getConversation(ConversationId id) throws ConversationException { + return getConversationContainer().getConversation(id); + } + + public ConversationId parseConversationId(String encodedId) throws ConversationException { + try { + return new SimpleConversationId(Integer.valueOf(encodedId)); + } catch (NumberFormatException e) { + throw new BadlyFormattedConversationIdException(encodedId, e); + } + } + + // hooks for subclassing + + protected ConversationContainer createConversationContainer() { + return new ConversationContainer(maxConversations, sessionKey); + } + + /** + * Obtain the conversation container from the session. Create a new empty container and add it to the session if no + * existing container can be found. + */ + protected final ConversationContainer getConversationContainer() { + SharedAttributeMap sessionMap = ExternalContextHolder.getExternalContext().getSessionMap(); + synchronized (sessionMap.getMutex()) { + ConversationContainer container = (ConversationContainer) sessionMap.get(sessionKey); + if (container == null) { + container = createConversationContainer(); + sessionMap.put(sessionKey, container); + } + return container; + } + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/Annotated.java b/spring-webflow/src/main/java/org/springframework/webflow/core/Annotated.java index 14a2ed27..e08d0e95 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/Annotated.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/Annotated.java @@ -1,47 +1,47 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core; - -import org.springframework.webflow.core.collection.MutableAttributeMap; - -/** - * An interface to be implemented by objects that are annotated with attributes they wish to expose to clients. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface Annotated { - - /** - * Returns a short summary of this object, suitable for display as an icon caption or tool tip. - * @return the caption - */ - String getCaption(); - - /** - * Returns a longer, more detailed description of this object. - * @return the description - */ - String getDescription(); - - /** - * Returns a attribute map containing the attributes annotating this object. These attributes provide descriptive - * characteristics or properties that may affect object behavior. - * @return the attribute map - */ - MutableAttributeMap getAttributes(); - -} +/* + * Copyright 2004-2012 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 + * + * https://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.core; + +import org.springframework.webflow.core.collection.MutableAttributeMap; + +/** + * An interface to be implemented by objects that are annotated with attributes they wish to expose to clients. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface Annotated { + + /** + * Returns a short summary of this object, suitable for display as an icon caption or tool tip. + * @return the caption + */ + String getCaption(); + + /** + * Returns a longer, more detailed description of this object. + * @return the description + */ + String getDescription(); + + /** + * Returns a attribute map containing the attributes annotating this object. These attributes provide descriptive + * characteristics or properties that may affect object behavior. + * @return the attribute map + */ + MutableAttributeMap getAttributes(); + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/AnnotatedObject.java b/spring-webflow/src/main/java/org/springframework/webflow/core/AnnotatedObject.java index b4f63cbb..384d66b9 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/AnnotatedObject.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/AnnotatedObject.java @@ -1,79 +1,79 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core; - -import org.springframework.webflow.core.collection.LocalAttributeMap; -import org.springframework.webflow.core.collection.MutableAttributeMap; - -/** - * A base class for all objects in the web flow system that support annotation using arbitrary properties. Mainly used - * to ensure consistent configuration of properties for all annotated objects. - * - * @author Erwin Vervaet - * @author Keith Donald - */ -public abstract class AnnotatedObject implements Annotated { - - /** - * The caption property name ("caption"). A caption is also known as a "short description" and may be used in a GUI - * tooltip. - */ - public static final String CAPTION_PROPERTY = "caption"; - - /** - * The long description property name ("description"). A description provides additional, free-form detail about - * this object and might be shown in a GUI text area. - */ - public static final String DESCRIPTION_PROPERTY = "description"; - - /** - * Additional properties further describing this object. The properties set in this map may be arbitrary. - */ - private LocalAttributeMap attributes = new LocalAttributeMap<>(); - - // implementing Annotated - - public String getCaption() { - return attributes.getString(CAPTION_PROPERTY); - } - - public String getDescription() { - return attributes.getString(DESCRIPTION_PROPERTY); - } - - public MutableAttributeMap getAttributes() { - return attributes; - } - - // mutators - - /** - * Sets the short description (suitable for display in a tooltip). - * @param caption the caption - */ - public void setCaption(String caption) { - attributes.put(CAPTION_PROPERTY, caption); - } - - /** - * Sets the long description. - * @param description the long description - */ - public void setDescription(String description) { - attributes.put(DESCRIPTION_PROPERTY, description); - } - -} +/* + * Copyright 2004-2012 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 + * + * https://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.core; + +import org.springframework.webflow.core.collection.LocalAttributeMap; +import org.springframework.webflow.core.collection.MutableAttributeMap; + +/** + * A base class for all objects in the web flow system that support annotation using arbitrary properties. Mainly used + * to ensure consistent configuration of properties for all annotated objects. + * + * @author Erwin Vervaet + * @author Keith Donald + */ +public abstract class AnnotatedObject implements Annotated { + + /** + * The caption property name ("caption"). A caption is also known as a "short description" and may be used in a GUI + * tooltip. + */ + public static final String CAPTION_PROPERTY = "caption"; + + /** + * The long description property name ("description"). A description provides additional, free-form detail about + * this object and might be shown in a GUI text area. + */ + public static final String DESCRIPTION_PROPERTY = "description"; + + /** + * Additional properties further describing this object. The properties set in this map may be arbitrary. + */ + private LocalAttributeMap attributes = new LocalAttributeMap<>(); + + // implementing Annotated + + public String getCaption() { + return attributes.getString(CAPTION_PROPERTY); + } + + public String getDescription() { + return attributes.getString(DESCRIPTION_PROPERTY); + } + + public MutableAttributeMap getAttributes() { + return attributes; + } + + // mutators + + /** + * Sets the short description (suitable for display in a tooltip). + * @param caption the caption + */ + public void setCaption(String caption) { + attributes.put(CAPTION_PROPERTY, caption); + } + + /** + * Sets the long description. + * @param description the long description + */ + public void setDescription(String description) { + attributes.put(DESCRIPTION_PROPERTY, description); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/FlowException.java b/spring-webflow/src/main/java/org/springframework/webflow/core/FlowException.java index b90d1d0d..8f7d9d3f 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/FlowException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/FlowException.java @@ -1,44 +1,44 @@ -/* - * 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 - * - * https://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.core; - -/** - * Root class for exceptions thrown by the Spring Web Flow system. All other exceptions within the system should be - * assignable to this class. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public abstract class FlowException extends RuntimeException { - - /** - * Creates a new flow exception. - * @param msg the message - * @param cause the cause - */ - public FlowException(String msg, Throwable cause) { - super(msg, cause); - } - - /** - * Creates a new flow exception. - * @param msg the message - */ - public FlowException(String msg) { - super(msg); - } - +/* + * 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 + * + * https://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.core; + +/** + * Root class for exceptions thrown by the Spring Web Flow system. All other exceptions within the system should be + * assignable to this class. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public abstract class FlowException extends RuntimeException { + + /** + * Creates a new flow exception. + * @param msg the message + * @param cause the cause + */ + public FlowException(String msg, Throwable cause) { + super(msg, cause); + } + + /** + * Creates a new flow exception. + * @param msg the message + */ + public FlowException(String msg) { + super(msg); + } + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMap.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMap.java index 94274ccb..cb2aeacb 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMap.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMap.java @@ -1,315 +1,315 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -import java.util.Collection; - -import org.springframework.binding.collection.MapAdaptable; - -/** - * An immutable interface for accessing attributes in a backing map with string keys. - *

- * Implementations can optionally support {@link AttributeMapBindingListener listeners} that will be notified when - * they're bound in or unbound from the map. - * - * @author Keith Donald - */ -public interface AttributeMap extends MapAdaptable { - - /** - * Get an attribute value out of this map, returning null if not found. - * @param attributeName the attribute name - * @return the attribute value - */ - V get(String attributeName); - - /** - * Returns the size of this map. - * @return the number of entries in the map - */ - int size(); - - /** - * Is this attribute map empty with a size of 0? - * @return true if empty, false if not - */ - boolean isEmpty(); - - /** - * Does the attribute with the provided name exist in this map? - * @param attributeName the attribute name - * @return true if so, false otherwise - */ - boolean contains(String attributeName); - - /** - * Does the attribute with the provided name exist in this map and is its value of the specified required type? - * @param attributeName the attribute name - * @param requiredType the required class of the attribute value - * @return true if so, false otherwise - * @throws IllegalArgumentException when the value is not of the required type - */ - boolean contains(String attributeName, Class requiredType) throws IllegalArgumentException; - - /** - * Get an attribute value, returning the default value if no value is found. - * @param attributeName the name of the attribute - * @param defaultValue the default value - * @return the attribute value, falling back to the default if no such attribute exists - */ - V get(String attributeName, V defaultValue); - - /** - * Get an attribute value, asserting the value is of the required type. - * @param attributeName the name of the attribute - * @param requiredType the required type of the attribute value - * @return the attribute value, or null if not found - * @throws IllegalArgumentException when the value is not of the required type - */ - T get(String attributeName, Class requiredType) throws IllegalArgumentException; - - /** - * Get an attribute value, asserting the value is of the required type and returning the default value if not found. - * @param attributeName the name of the attribute - * @param requiredType the value required type - * @param defaultValue the default value - * @return the attribute value, or the default if not found - * @throws IllegalArgumentException when the value (if found) is not of the required type - */ - T get(String attributeName, Class requiredType, T defaultValue) - throws IllegalStateException; - - /** - * Get the value of a required attribute, throwing an exception of no attribute is found. - * @param attributeName the name of the attribute - * @return the attribute value - * @throws IllegalArgumentException when the attribute is not found - */ - V getRequired(String attributeName) throws IllegalArgumentException; - - /** - * Get the value of a required attribute and make sure it is of the required type. - * @param attributeName name of the attribute to get - * @param requiredType the required type of the attribute value - * @return the attribute value - * @throws IllegalArgumentException when the attribute is not found or not of the required type - */ - T getRequired(String attributeName, Class requiredType) throws IllegalArgumentException; - - /** - * Returns a string attribute value in the map, returning null if no value was found. - * @param attributeName the attribute name - * @return the string attribute value - * @throws IllegalArgumentException if the attribute is present but not a string - */ - String getString(String attributeName) throws IllegalArgumentException; - - /** - * Returns a string attribute value in the map, returning the default value if no value was found. - * @param attributeName the attribute name - * @param defaultValue the default - * @return the string attribute value - * @throws IllegalArgumentException if the attribute is present but not a string - */ - String getString(String attributeName, String defaultValue) throws IllegalArgumentException; - - /** - * Returns a string attribute value in the map, throwing an exception if the attribute is not present and of the - * correct type. - * @param attributeName the attribute name - * @return the string attribute value - * @throws IllegalArgumentException if the attribute is not present or present but not a string - */ - String getRequiredString(String attributeName) throws IllegalArgumentException; - - /** - * Returns a collection attribute value in the map. - * @param attributeName the attribute name - * @return the collection attribute value - * @throws IllegalArgumentException if the attribute is present but not a collection - */ - Collection getCollection(String attributeName) throws IllegalArgumentException; - - /** - * Returns a collection attribute value in the map and make sure it is of the required type. - * @param attributeName the attribute name - * @param requiredType the required type of the attribute value - * @return the collection attribute value - * @throws IllegalArgumentException if the attribute is present but not a collection of the required type - */ - > T getCollection(String attributeName, Class requiredType) - throws IllegalArgumentException; - - /** - * Returns a collection attribute value in the map, throwing an exception if the attribute is not present or not a - * collection. - * @param attributeName the attribute name - * @return the collection attribute value - * @throws IllegalArgumentException if the attribute is not present or is present but not a collection - */ - Collection getRequiredCollection(String attributeName) throws IllegalArgumentException; - - /** - * Returns a collection attribute value in the map, throwing an exception if the attribute is not present or not a - * collection of the required type. - * @param attributeName the attribute name - * @param requiredType the required collection type - * @return the collection attribute value - * @throws IllegalArgumentException if the attribute is not present or is present but not a collection of the - * required type - */ - > T getRequiredCollection(String attributeName, Class requiredType) - throws IllegalArgumentException; - - /** - * Returns an array attribute value in the map and makes sure it is of the required type. - * @param attributeName the attribute name - * @param requiredType the required type of the attribute value - * @return the array attribute value - * @throws IllegalArgumentException if the attribute is present but not an array of the required type - */ - T[] getArray(String attributeName, Class requiredType) - throws IllegalArgumentException; - - /** - * Returns an array attribute value in the map, throwing an exception if the attribute is not present or not an - * array of the required type. - * @param attributeName the attribute name - * @param requiredType the required array type - * @return the collection attribute value - * @throws IllegalArgumentException if the attribute is not present or is present but not a array of the required - * type - */ - T[] getRequiredArray(String attributeName, Class requiredType) - throws IllegalArgumentException; - - /** - * Returns a number attribute value in the map that is of the specified type, returning null if no - * value was found. - * @param attributeName the attribute name - * @param requiredType the required number type - * @return the number attribute value - * @throws IllegalArgumentException if the attribute is present but not a number of the required type - */ - T getNumber(String attributeName, Class requiredType) throws IllegalArgumentException; - - /** - * Returns a number attribute value in the map of the specified type, returning the default value if no value was - * found. - * @param attributeName the attribute name - * @param defaultValue the default - * @return the number attribute value - * @throws IllegalArgumentException if the attribute is present but not a number of the required type - */ - T getNumber(String attributeName, Class requiredType, T defaultValue) - throws IllegalArgumentException; - - /** - * Returns a number attribute value in the map, throwing an exception if the attribute is not present and of the - * correct type. - * @param attributeName the attribute name - * @return the number attribute value - * @throws IllegalArgumentException if the attribute is not present or present but not a number of the required type - */ - T getRequiredNumber(String attributeName, Class requiredType) - throws IllegalArgumentException; - - /** - * Returns an integer attribute value in the map, returning null if no value was found. - * @param attributeName the attribute name - * @return the integer attribute value - * @throws IllegalArgumentException if the attribute is present but not an integer - */ - Integer getInteger(String attributeName) throws IllegalArgumentException; - - /** - * Returns an integer attribute value in the map, returning the default value if no value was found. - * @param attributeName the attribute name - * @param defaultValue the default - * @return the integer attribute value - * @throws IllegalArgumentException if the attribute is present but not an integer - */ - Integer getInteger(String attributeName, Integer defaultValue) throws IllegalArgumentException; - - /** - * Returns an integer attribute value in the map, throwing an exception if the attribute is not present and of the - * correct type. - * @param attributeName the attribute name - * @return the integer attribute value - * @throws IllegalArgumentException if the attribute is not present or present but not an integer - */ - Integer getRequiredInteger(String attributeName) throws IllegalArgumentException; - - /** - * Returns a long attribute value in the map, returning null if no value was found. - * @param attributeName the attribute name - * @return the long attribute value - * @throws IllegalArgumentException if the attribute is present but not a long - */ - Long getLong(String attributeName) throws IllegalArgumentException; - - /** - * Returns a long attribute value in the map, returning the default value if no value was found. - * @param attributeName the attribute name - * @param defaultValue the default - * @return the long attribute value - * @throws IllegalArgumentException if the attribute is present but not a long - */ - Long getLong(String attributeName, Long defaultValue) throws IllegalArgumentException; - - /** - * Returns a long attribute value in the map, throwing an exception if the attribute is not present and of the - * correct type. - * @param attributeName the attribute name - * @return the long attribute value - * @throws IllegalArgumentException if the attribute is not present or present but not a long - */ - Long getRequiredLong(String attributeName) throws IllegalArgumentException; - - /** - * Returns a boolean attribute value in the map, returning null if no value was found. - * @param attributeName the attribute name - * @return the long attribute value - * @throws IllegalArgumentException if the attribute is present but not a boolean - */ - Boolean getBoolean(String attributeName) throws IllegalArgumentException; - - /** - * Returns a boolean attribute value in the map, returning the default value if no value was found. - * @param attributeName the attribute name - * @param defaultValue the default - * @return the boolean attribute value - * @throws IllegalArgumentException if the attribute is present but not a boolean - */ - Boolean getBoolean(String attributeName, Boolean defaultValue) throws IllegalArgumentException; - - /** - * Returns a boolean attribute value in the map, throwing an exception if the attribute is not present and of the - * correct type. - * @param attributeName the attribute name - * @return the boolean attribute value - * @throws IllegalArgumentException if the attribute is not present or present but is not a boolean - */ - Boolean getRequiredBoolean(String attributeName) throws IllegalArgumentException; - - /** - * Returns a new attribute map containing the union of this map with the provided map. - * @param attributes the map to combine with this map - * @return a new, combined map - */ - AttributeMap union(AttributeMap attributes); - -} +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +import java.util.Collection; + +import org.springframework.binding.collection.MapAdaptable; + +/** + * An immutable interface for accessing attributes in a backing map with string keys. + *

+ * Implementations can optionally support {@link AttributeMapBindingListener listeners} that will be notified when + * they're bound in or unbound from the map. + * + * @author Keith Donald + */ +public interface AttributeMap extends MapAdaptable { + + /** + * Get an attribute value out of this map, returning null if not found. + * @param attributeName the attribute name + * @return the attribute value + */ + V get(String attributeName); + + /** + * Returns the size of this map. + * @return the number of entries in the map + */ + int size(); + + /** + * Is this attribute map empty with a size of 0? + * @return true if empty, false if not + */ + boolean isEmpty(); + + /** + * Does the attribute with the provided name exist in this map? + * @param attributeName the attribute name + * @return true if so, false otherwise + */ + boolean contains(String attributeName); + + /** + * Does the attribute with the provided name exist in this map and is its value of the specified required type? + * @param attributeName the attribute name + * @param requiredType the required class of the attribute value + * @return true if so, false otherwise + * @throws IllegalArgumentException when the value is not of the required type + */ + boolean contains(String attributeName, Class requiredType) throws IllegalArgumentException; + + /** + * Get an attribute value, returning the default value if no value is found. + * @param attributeName the name of the attribute + * @param defaultValue the default value + * @return the attribute value, falling back to the default if no such attribute exists + */ + V get(String attributeName, V defaultValue); + + /** + * Get an attribute value, asserting the value is of the required type. + * @param attributeName the name of the attribute + * @param requiredType the required type of the attribute value + * @return the attribute value, or null if not found + * @throws IllegalArgumentException when the value is not of the required type + */ + T get(String attributeName, Class requiredType) throws IllegalArgumentException; + + /** + * Get an attribute value, asserting the value is of the required type and returning the default value if not found. + * @param attributeName the name of the attribute + * @param requiredType the value required type + * @param defaultValue the default value + * @return the attribute value, or the default if not found + * @throws IllegalArgumentException when the value (if found) is not of the required type + */ + T get(String attributeName, Class requiredType, T defaultValue) + throws IllegalStateException; + + /** + * Get the value of a required attribute, throwing an exception of no attribute is found. + * @param attributeName the name of the attribute + * @return the attribute value + * @throws IllegalArgumentException when the attribute is not found + */ + V getRequired(String attributeName) throws IllegalArgumentException; + + /** + * Get the value of a required attribute and make sure it is of the required type. + * @param attributeName name of the attribute to get + * @param requiredType the required type of the attribute value + * @return the attribute value + * @throws IllegalArgumentException when the attribute is not found or not of the required type + */ + T getRequired(String attributeName, Class requiredType) throws IllegalArgumentException; + + /** + * Returns a string attribute value in the map, returning null if no value was found. + * @param attributeName the attribute name + * @return the string attribute value + * @throws IllegalArgumentException if the attribute is present but not a string + */ + String getString(String attributeName) throws IllegalArgumentException; + + /** + * Returns a string attribute value in the map, returning the default value if no value was found. + * @param attributeName the attribute name + * @param defaultValue the default + * @return the string attribute value + * @throws IllegalArgumentException if the attribute is present but not a string + */ + String getString(String attributeName, String defaultValue) throws IllegalArgumentException; + + /** + * Returns a string attribute value in the map, throwing an exception if the attribute is not present and of the + * correct type. + * @param attributeName the attribute name + * @return the string attribute value + * @throws IllegalArgumentException if the attribute is not present or present but not a string + */ + String getRequiredString(String attributeName) throws IllegalArgumentException; + + /** + * Returns a collection attribute value in the map. + * @param attributeName the attribute name + * @return the collection attribute value + * @throws IllegalArgumentException if the attribute is present but not a collection + */ + Collection getCollection(String attributeName) throws IllegalArgumentException; + + /** + * Returns a collection attribute value in the map and make sure it is of the required type. + * @param attributeName the attribute name + * @param requiredType the required type of the attribute value + * @return the collection attribute value + * @throws IllegalArgumentException if the attribute is present but not a collection of the required type + */ + > T getCollection(String attributeName, Class requiredType) + throws IllegalArgumentException; + + /** + * Returns a collection attribute value in the map, throwing an exception if the attribute is not present or not a + * collection. + * @param attributeName the attribute name + * @return the collection attribute value + * @throws IllegalArgumentException if the attribute is not present or is present but not a collection + */ + Collection getRequiredCollection(String attributeName) throws IllegalArgumentException; + + /** + * Returns a collection attribute value in the map, throwing an exception if the attribute is not present or not a + * collection of the required type. + * @param attributeName the attribute name + * @param requiredType the required collection type + * @return the collection attribute value + * @throws IllegalArgumentException if the attribute is not present or is present but not a collection of the + * required type + */ + > T getRequiredCollection(String attributeName, Class requiredType) + throws IllegalArgumentException; + + /** + * Returns an array attribute value in the map and makes sure it is of the required type. + * @param attributeName the attribute name + * @param requiredType the required type of the attribute value + * @return the array attribute value + * @throws IllegalArgumentException if the attribute is present but not an array of the required type + */ + T[] getArray(String attributeName, Class requiredType) + throws IllegalArgumentException; + + /** + * Returns an array attribute value in the map, throwing an exception if the attribute is not present or not an + * array of the required type. + * @param attributeName the attribute name + * @param requiredType the required array type + * @return the collection attribute value + * @throws IllegalArgumentException if the attribute is not present or is present but not a array of the required + * type + */ + T[] getRequiredArray(String attributeName, Class requiredType) + throws IllegalArgumentException; + + /** + * Returns a number attribute value in the map that is of the specified type, returning null if no + * value was found. + * @param attributeName the attribute name + * @param requiredType the required number type + * @return the number attribute value + * @throws IllegalArgumentException if the attribute is present but not a number of the required type + */ + T getNumber(String attributeName, Class requiredType) throws IllegalArgumentException; + + /** + * Returns a number attribute value in the map of the specified type, returning the default value if no value was + * found. + * @param attributeName the attribute name + * @param defaultValue the default + * @return the number attribute value + * @throws IllegalArgumentException if the attribute is present but not a number of the required type + */ + T getNumber(String attributeName, Class requiredType, T defaultValue) + throws IllegalArgumentException; + + /** + * Returns a number attribute value in the map, throwing an exception if the attribute is not present and of the + * correct type. + * @param attributeName the attribute name + * @return the number attribute value + * @throws IllegalArgumentException if the attribute is not present or present but not a number of the required type + */ + T getRequiredNumber(String attributeName, Class requiredType) + throws IllegalArgumentException; + + /** + * Returns an integer attribute value in the map, returning null if no value was found. + * @param attributeName the attribute name + * @return the integer attribute value + * @throws IllegalArgumentException if the attribute is present but not an integer + */ + Integer getInteger(String attributeName) throws IllegalArgumentException; + + /** + * Returns an integer attribute value in the map, returning the default value if no value was found. + * @param attributeName the attribute name + * @param defaultValue the default + * @return the integer attribute value + * @throws IllegalArgumentException if the attribute is present but not an integer + */ + Integer getInteger(String attributeName, Integer defaultValue) throws IllegalArgumentException; + + /** + * Returns an integer attribute value in the map, throwing an exception if the attribute is not present and of the + * correct type. + * @param attributeName the attribute name + * @return the integer attribute value + * @throws IllegalArgumentException if the attribute is not present or present but not an integer + */ + Integer getRequiredInteger(String attributeName) throws IllegalArgumentException; + + /** + * Returns a long attribute value in the map, returning null if no value was found. + * @param attributeName the attribute name + * @return the long attribute value + * @throws IllegalArgumentException if the attribute is present but not a long + */ + Long getLong(String attributeName) throws IllegalArgumentException; + + /** + * Returns a long attribute value in the map, returning the default value if no value was found. + * @param attributeName the attribute name + * @param defaultValue the default + * @return the long attribute value + * @throws IllegalArgumentException if the attribute is present but not a long + */ + Long getLong(String attributeName, Long defaultValue) throws IllegalArgumentException; + + /** + * Returns a long attribute value in the map, throwing an exception if the attribute is not present and of the + * correct type. + * @param attributeName the attribute name + * @return the long attribute value + * @throws IllegalArgumentException if the attribute is not present or present but not a long + */ + Long getRequiredLong(String attributeName) throws IllegalArgumentException; + + /** + * Returns a boolean attribute value in the map, returning null if no value was found. + * @param attributeName the attribute name + * @return the long attribute value + * @throws IllegalArgumentException if the attribute is present but not a boolean + */ + Boolean getBoolean(String attributeName) throws IllegalArgumentException; + + /** + * Returns a boolean attribute value in the map, returning the default value if no value was found. + * @param attributeName the attribute name + * @param defaultValue the default + * @return the boolean attribute value + * @throws IllegalArgumentException if the attribute is present but not a boolean + */ + Boolean getBoolean(String attributeName, Boolean defaultValue) throws IllegalArgumentException; + + /** + * Returns a boolean attribute value in the map, throwing an exception if the attribute is not present and of the + * correct type. + * @param attributeName the attribute name + * @return the boolean attribute value + * @throws IllegalArgumentException if the attribute is not present or present but is not a boolean + */ + Boolean getRequiredBoolean(String attributeName) throws IllegalArgumentException; + + /** + * Returns a new attribute map containing the union of this map with the provided map. + * @param attributes the map to combine with this map + * @return a new, combined map + */ + AttributeMap union(AttributeMap attributes); + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMapBindingEvent.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMapBindingEvent.java index 854a6d6f..46c9bdef 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMapBindingEvent.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMapBindingEvent.java @@ -1,59 +1,59 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -import java.util.EventObject; - -/** - * Holder for information about the binding or unbinding event in an {@link AttributeMap}. - * - * @see AttributeMapBindingListener - * - * @author Ben Hale - */ -public class AttributeMapBindingEvent extends EventObject { - - private String attributeName; - - private Object attributeValue; - - /** - * Creates an event for map binding that contains information about the event. - * @param source the source map that this attribute was bound in - * @param attributeName the name that this attribute was bound with - * @param attributeValue the attribute - */ - public AttributeMapBindingEvent(AttributeMap source, String attributeName, Object attributeValue) { - super(source); - this.source = source; - this.attributeName = attributeName; - this.attributeValue = attributeValue; - } - - /** - * Returns the name the attribute was bound with. - */ - public String getAttributeName() { - return attributeName; - } - - /** - * Returns the value of the attribute. - */ - public Object getAttributeValue() { - return attributeValue; - } +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +import java.util.EventObject; + +/** + * Holder for information about the binding or unbinding event in an {@link AttributeMap}. + * + * @see AttributeMapBindingListener + * + * @author Ben Hale + */ +public class AttributeMapBindingEvent extends EventObject { + + private String attributeName; + + private Object attributeValue; + + /** + * Creates an event for map binding that contains information about the event. + * @param source the source map that this attribute was bound in + * @param attributeName the name that this attribute was bound with + * @param attributeValue the attribute + */ + public AttributeMapBindingEvent(AttributeMap source, String attributeName, Object attributeValue) { + super(source); + this.source = source; + this.attributeName = attributeName; + this.attributeValue = attributeValue; + } + + /** + * Returns the name the attribute was bound with. + */ + public String getAttributeName() { + return attributeName; + } + + /** + * Returns the value of the attribute. + */ + public Object getAttributeValue() { + return attributeValue; + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMapBindingListener.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMapBindingListener.java index a4de0f68..1ef5cf5a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMapBindingListener.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/AttributeMapBindingListener.java @@ -1,40 +1,40 @@ -/* - * 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 - * - * https://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.core.collection; - -/** - * Causes an object to be notified when it is bound or unbound from an {@link AttributeMap}. - *

- * Note that this is an optional feature and not all {@link AttributeMap} implementations support it. - * - * @see AttributeMap - * - * @author Ben Hale - */ -public interface AttributeMapBindingListener { - - /** - * Called when the implementing instance is bound into an AttributeMap. - * @param event information about the binding event - */ - void valueBound(AttributeMapBindingEvent event); - - /** - * Called when the implementing instance is unbound from an AttributeMap. - * @param event information about the unbinding event - */ - void valueUnbound(AttributeMapBindingEvent event); +/* + * 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 + * + * https://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.core.collection; + +/** + * Causes an object to be notified when it is bound or unbound from an {@link AttributeMap}. + *

+ * Note that this is an optional feature and not all {@link AttributeMap} implementations support it. + * + * @see AttributeMap + * + * @author Ben Hale + */ +public interface AttributeMapBindingListener { + + /** + * Called when the implementing instance is bound into an AttributeMap. + * @param event information about the binding event + */ + void valueBound(AttributeMapBindingEvent event); + + /** + * Called when the implementing instance is unbound from an AttributeMap. + * @param event information about the unbinding event + */ + void valueUnbound(AttributeMapBindingEvent event); } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/CollectionUtils.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/CollectionUtils.java index 376d1c50..547aa918 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/CollectionUtils.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/CollectionUtils.java @@ -1,140 +1,140 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; - -/** - * A utility class for working with attribute and parameter collections used by Spring Web FLow. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class CollectionUtils { - - /** - * The shared, singleton empty iterator instance. - */ - @SuppressWarnings("rawtypes") - public static final Iterator EMPTY_ITERATOR = new EmptyIterator(); - - /** - * The shared, singleton empty attribute map instance. - */ - public static final AttributeMap EMPTY_ATTRIBUTE_MAP = new LocalAttributeMap<>(Collections.emptyMap()); - - /** - * Private constructor to avoid instantiation. - */ - private CollectionUtils() { - } - - @SuppressWarnings("unchecked") - public static Iterator emptyIterator() { - return EMPTY_ITERATOR; - } - - /** - * Factory method that adapts an enumeration to an iterator. - * @param enumeration the enumeration - * @return the iterator - */ - public static Iterator toIterator(Enumeration enumeration) { - return new EnumerationIterator<>(enumeration); - } - - /** - * Factory method that returns a unmodifiable attribute map with a single entry. - * @param attributeName the attribute name - * @param attributeValue the attribute value - * @return the unmodifiable map with a single element - */ - public static AttributeMap singleEntryMap(String attributeName, V attributeValue) { - return new LocalAttributeMap<>(attributeName, attributeValue); - } - - /** - * Add all given objects to given target list. No duplicates will be added. The contains() method of the given - * target list will be used to determine whether or not an object is already in the list. - * @param target the collection to which to objects will be added - * @param objects the objects to add - * @return whether or not the target collection changed - */ - @SuppressWarnings("unchecked") - public static boolean addAllNoDuplicates(List target, T... objects) { - if (objects == null || objects.length == 0) { - return false; - } else { - boolean changed = false; - for (T object : objects) { - if (!target.contains(object)) { - target.add(object); - changed = true; - } - } - return changed; - } - } - - /** - * Iterator iterating over no elements (hasNext() always returns false). - */ - private static class EmptyIterator implements Iterator, Serializable { - - private EmptyIterator() { - } - - public boolean hasNext() { - return false; - } - - public E next() { - throw new UnsupportedOperationException("There are no elements"); - } - - public void remove() { - throw new UnsupportedOperationException("There are no elements"); - } - } - - /** - * Iterator wrapping an Enumeration. - */ - private static class EnumerationIterator implements Iterator { - - private Enumeration enumeration; - - public EnumerationIterator(Enumeration enumeration) { - this.enumeration = enumeration; - } - - public boolean hasNext() { - return enumeration.hasMoreElements(); - } - - public E next() { - return enumeration.nextElement(); - } - - public void remove() throws UnsupportedOperationException { - throw new UnsupportedOperationException("Not supported"); - } - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +/** + * A utility class for working with attribute and parameter collections used by Spring Web FLow. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class CollectionUtils { + + /** + * The shared, singleton empty iterator instance. + */ + @SuppressWarnings("rawtypes") + public static final Iterator EMPTY_ITERATOR = new EmptyIterator(); + + /** + * The shared, singleton empty attribute map instance. + */ + public static final AttributeMap EMPTY_ATTRIBUTE_MAP = new LocalAttributeMap<>(Collections.emptyMap()); + + /** + * Private constructor to avoid instantiation. + */ + private CollectionUtils() { + } + + @SuppressWarnings("unchecked") + public static Iterator emptyIterator() { + return EMPTY_ITERATOR; + } + + /** + * Factory method that adapts an enumeration to an iterator. + * @param enumeration the enumeration + * @return the iterator + */ + public static Iterator toIterator(Enumeration enumeration) { + return new EnumerationIterator<>(enumeration); + } + + /** + * Factory method that returns a unmodifiable attribute map with a single entry. + * @param attributeName the attribute name + * @param attributeValue the attribute value + * @return the unmodifiable map with a single element + */ + public static AttributeMap singleEntryMap(String attributeName, V attributeValue) { + return new LocalAttributeMap<>(attributeName, attributeValue); + } + + /** + * Add all given objects to given target list. No duplicates will be added. The contains() method of the given + * target list will be used to determine whether or not an object is already in the list. + * @param target the collection to which to objects will be added + * @param objects the objects to add + * @return whether or not the target collection changed + */ + @SuppressWarnings("unchecked") + public static boolean addAllNoDuplicates(List target, T... objects) { + if (objects == null || objects.length == 0) { + return false; + } else { + boolean changed = false; + for (T object : objects) { + if (!target.contains(object)) { + target.add(object); + changed = true; + } + } + return changed; + } + } + + /** + * Iterator iterating over no elements (hasNext() always returns false). + */ + private static class EmptyIterator implements Iterator, Serializable { + + private EmptyIterator() { + } + + public boolean hasNext() { + return false; + } + + public E next() { + throw new UnsupportedOperationException("There are no elements"); + } + + public void remove() { + throw new UnsupportedOperationException("There are no elements"); + } + } + + /** + * Iterator wrapping an Enumeration. + */ + private static class EnumerationIterator implements Iterator { + + private Enumeration enumeration; + + public EnumerationIterator(Enumeration enumeration) { + this.enumeration = enumeration; + } + + public boolean hasNext() { + return enumeration.hasMoreElements(); + } + + public E next() { + return enumeration.nextElement(); + } + + public void remove() throws UnsupportedOperationException { + throw new UnsupportedOperationException("Not supported"); + } + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalAttributeMap.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalAttributeMap.java index 2816d100..935546d4 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalAttributeMap.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalAttributeMap.java @@ -1,344 +1,344 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.binding.collection.MapAccessor; -import org.springframework.core.style.StylerUtils; -import org.springframework.util.Assert; - -/** - * A generic, mutable attribute map with string keys. - * - * @author Keith Donald - */ -public class LocalAttributeMap implements MutableAttributeMap, Serializable { - - /** - * The backing map storing the attributes. - */ - private Map attributes; - - /** - * A helper for accessing attributes. Marked transient and restored on deserialization. - */ - private transient MapAccessor attributeAccessor; - - /** - * Creates a new attribute map, initially empty. - */ - public LocalAttributeMap() { - initAttributes(createTargetMap()); - } - - /** - * Creates a new attribute map, initially empty. - * @param size the initial size - * @param loadFactor the load factor - */ - public LocalAttributeMap(int size, int loadFactor) { - initAttributes(createTargetMap(size, loadFactor)); - } - - /** - * Creates a new attribute map with a single entry. - */ - public LocalAttributeMap(String attributeName, V attributeValue) { - initAttributes(createTargetMap(1, 1)); - put(attributeName, attributeValue); - } - - /** - * Creates a new attribute map wrapping the specified map. - */ - public LocalAttributeMap(Map map) { - Assert.notNull(map, "The target map is required"); - initAttributes(map); - } - - // implementing attribute map - - public Map asMap() { - return attributeAccessor.asMap(); - } - - public int size() { - return attributes.size(); - } - - public V get(String attributeName) { - return attributes.get(attributeName); - } - - public boolean isEmpty() { - return attributes.isEmpty(); - } - - public boolean contains(String attributeName) { - return attributes.containsKey(attributeName); - } - - public boolean contains(String attributeName, Class requiredType) throws IllegalArgumentException { - return attributeAccessor.containsKey(attributeName, requiredType); - } - - public V get(String attributeName, V defaultValue) { - return attributeAccessor.get(attributeName, defaultValue); - } - - public T get(String attributeName, Class requiredType) throws IllegalArgumentException { - return attributeAccessor.get(attributeName, requiredType); - } - - public T get(String attributeName, Class requiredType, T defaultValue) - throws IllegalStateException { - return attributeAccessor.get(attributeName, requiredType, defaultValue); - } - - public V getRequired(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getRequired(attributeName); - } - - public T getRequired(String attributeName, Class requiredType) throws IllegalArgumentException { - return attributeAccessor.getRequired(attributeName, requiredType); - } - - public String getString(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getString(attributeName); - } - - public String getString(String attributeName, String defaultValue) throws IllegalArgumentException { - return attributeAccessor.getString(attributeName, defaultValue); - } - - public String getRequiredString(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getRequiredString(attributeName); - } - - public Collection getCollection(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getCollection(attributeName); - } - - public > T getCollection(String attributeName, Class requiredType) - throws IllegalArgumentException { - return attributeAccessor.getCollection(attributeName, requiredType); - } - - public Collection getRequiredCollection(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getRequiredCollection(attributeName); - } - - public > T getRequiredCollection(String attributeName, Class requiredType) - throws IllegalArgumentException { - return attributeAccessor.getRequiredCollection(attributeName, requiredType); - } - - public T[] getArray(String attributeName, Class requiredType) - throws IllegalArgumentException { - return attributeAccessor.getArray(attributeName, requiredType); - } - - public T[] getRequiredArray(String attributeName, Class requiredType) - throws IllegalArgumentException { - return attributeAccessor.getRequiredArray(attributeName, requiredType); - } - - public T getNumber(String attributeName, Class requiredType) throws IllegalArgumentException { - return attributeAccessor.getNumber(attributeName, requiredType); - } - - public T getNumber(String attributeName, Class requiredType, T defaultValue) - throws IllegalArgumentException { - return attributeAccessor.getNumber(attributeName, requiredType, defaultValue); - } - - public T getRequiredNumber(String attributeName, Class requiredType) - throws IllegalArgumentException { - return attributeAccessor.getRequiredNumber(attributeName, requiredType); - } - - public Integer getInteger(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getInteger(attributeName); - } - - public Integer getInteger(String attributeName, Integer defaultValue) throws IllegalArgumentException { - return attributeAccessor.getInteger(attributeName, defaultValue); - } - - public Integer getRequiredInteger(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getRequiredInteger(attributeName); - } - - public Long getLong(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getLong(attributeName); - } - - public Long getLong(String attributeName, Long defaultValue) throws IllegalArgumentException { - return attributeAccessor.getLong(attributeName, defaultValue); - } - - public Long getRequiredLong(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getRequiredLong(attributeName); - } - - public Boolean getBoolean(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getBoolean(attributeName); - } - - public Boolean getBoolean(String attributeName, Boolean defaultValue) throws IllegalArgumentException { - return attributeAccessor.getBoolean(attributeName, defaultValue); - } - - public Boolean getRequiredBoolean(String attributeName) throws IllegalArgumentException { - return attributeAccessor.getRequiredBoolean(attributeName); - } - - public AttributeMap union(AttributeMap attributes) { - if (attributes == null) { - return new LocalAttributeMap<>(getMapInternal()); - } else { - Map map = createTargetMap(); - map.putAll(getMapInternal()); - map.putAll(attributes.asMap()); - return new LocalAttributeMap<>(map); - } - } - - // implementing MutableAttributeMap - - public V put(String attributeName, V attributeValue) { - return getMapInternal().put(attributeName, attributeValue); - } - - public MutableAttributeMap putAll(AttributeMap attributes) { - if (attributes == null) { - return this; - } - getMapInternal().putAll(attributes.asMap()); - return this; - } - - public MutableAttributeMap removeAll(MutableAttributeMap attributes) { - if (attributes == null) { - return this; - } - Map internal = getMapInternal(); - for (String attribute : attributes.asMap().keySet()) { - internal.remove(attribute); - } - return this; - } - - public Object remove(String attributeName) { - return getMapInternal().remove(attributeName); - } - - public Object extract(String attributeName) { - Map map = getMapInternal(); - if (map.containsKey(attributeName)) { - Object value = map.get(attributeName); - map.remove(attributeName); - return value; - } else { - return null; - } - } - - public MutableAttributeMap clear() throws UnsupportedOperationException { - getMapInternal().clear(); - return this; - } - - public MutableAttributeMap replaceWith(AttributeMap attributes) - throws UnsupportedOperationException { - clear(); - putAll(attributes); - return this; - } - - // helpers for subclasses - - /** - * Initializes this attribute map. - * @param attributes the attributes - */ - protected void initAttributes(Map attributes) { - this.attributes = attributes; - attributeAccessor = new MapAccessor<>(this.attributes); - } - - /** - * Returns the wrapped, modifiable map implementation. - */ - protected Map getMapInternal() { - return attributes; - } - - // helpers - - /** - * Factory method that returns the target map storing the data in this attribute map. - * @return the target map - */ - protected Map createTargetMap() { - return new HashMap<>(); - } - - /** - * Factory method that returns the target map storing the data in this attribute map. - * @param size the initial size of the map - * @param loadFactor the load factor - * @return the target map - */ - protected Map createTargetMap(int size, int loadFactor) { - return new HashMap<>(size, loadFactor); - } - - @SuppressWarnings("unchecked") - public boolean equals(Object o) { - if (!(o instanceof LocalAttributeMap)) { - return false; - } - LocalAttributeMap other = (LocalAttributeMap) o; - return getMapInternal().equals(other.getMapInternal()); - } - - public int hashCode() { - return getMapInternal().hashCode(); - } - - // custom serialization - - private void writeObject(ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - attributeAccessor = new MapAccessor<>(attributes); - } - - public String toString() { - return StylerUtils.style(attributes); - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.binding.collection.MapAccessor; +import org.springframework.core.style.StylerUtils; +import org.springframework.util.Assert; + +/** + * A generic, mutable attribute map with string keys. + * + * @author Keith Donald + */ +public class LocalAttributeMap implements MutableAttributeMap, Serializable { + + /** + * The backing map storing the attributes. + */ + private Map attributes; + + /** + * A helper for accessing attributes. Marked transient and restored on deserialization. + */ + private transient MapAccessor attributeAccessor; + + /** + * Creates a new attribute map, initially empty. + */ + public LocalAttributeMap() { + initAttributes(createTargetMap()); + } + + /** + * Creates a new attribute map, initially empty. + * @param size the initial size + * @param loadFactor the load factor + */ + public LocalAttributeMap(int size, int loadFactor) { + initAttributes(createTargetMap(size, loadFactor)); + } + + /** + * Creates a new attribute map with a single entry. + */ + public LocalAttributeMap(String attributeName, V attributeValue) { + initAttributes(createTargetMap(1, 1)); + put(attributeName, attributeValue); + } + + /** + * Creates a new attribute map wrapping the specified map. + */ + public LocalAttributeMap(Map map) { + Assert.notNull(map, "The target map is required"); + initAttributes(map); + } + + // implementing attribute map + + public Map asMap() { + return attributeAccessor.asMap(); + } + + public int size() { + return attributes.size(); + } + + public V get(String attributeName) { + return attributes.get(attributeName); + } + + public boolean isEmpty() { + return attributes.isEmpty(); + } + + public boolean contains(String attributeName) { + return attributes.containsKey(attributeName); + } + + public boolean contains(String attributeName, Class requiredType) throws IllegalArgumentException { + return attributeAccessor.containsKey(attributeName, requiredType); + } + + public V get(String attributeName, V defaultValue) { + return attributeAccessor.get(attributeName, defaultValue); + } + + public T get(String attributeName, Class requiredType) throws IllegalArgumentException { + return attributeAccessor.get(attributeName, requiredType); + } + + public T get(String attributeName, Class requiredType, T defaultValue) + throws IllegalStateException { + return attributeAccessor.get(attributeName, requiredType, defaultValue); + } + + public V getRequired(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getRequired(attributeName); + } + + public T getRequired(String attributeName, Class requiredType) throws IllegalArgumentException { + return attributeAccessor.getRequired(attributeName, requiredType); + } + + public String getString(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getString(attributeName); + } + + public String getString(String attributeName, String defaultValue) throws IllegalArgumentException { + return attributeAccessor.getString(attributeName, defaultValue); + } + + public String getRequiredString(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getRequiredString(attributeName); + } + + public Collection getCollection(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getCollection(attributeName); + } + + public > T getCollection(String attributeName, Class requiredType) + throws IllegalArgumentException { + return attributeAccessor.getCollection(attributeName, requiredType); + } + + public Collection getRequiredCollection(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getRequiredCollection(attributeName); + } + + public > T getRequiredCollection(String attributeName, Class requiredType) + throws IllegalArgumentException { + return attributeAccessor.getRequiredCollection(attributeName, requiredType); + } + + public T[] getArray(String attributeName, Class requiredType) + throws IllegalArgumentException { + return attributeAccessor.getArray(attributeName, requiredType); + } + + public T[] getRequiredArray(String attributeName, Class requiredType) + throws IllegalArgumentException { + return attributeAccessor.getRequiredArray(attributeName, requiredType); + } + + public T getNumber(String attributeName, Class requiredType) throws IllegalArgumentException { + return attributeAccessor.getNumber(attributeName, requiredType); + } + + public T getNumber(String attributeName, Class requiredType, T defaultValue) + throws IllegalArgumentException { + return attributeAccessor.getNumber(attributeName, requiredType, defaultValue); + } + + public T getRequiredNumber(String attributeName, Class requiredType) + throws IllegalArgumentException { + return attributeAccessor.getRequiredNumber(attributeName, requiredType); + } + + public Integer getInteger(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getInteger(attributeName); + } + + public Integer getInteger(String attributeName, Integer defaultValue) throws IllegalArgumentException { + return attributeAccessor.getInteger(attributeName, defaultValue); + } + + public Integer getRequiredInteger(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getRequiredInteger(attributeName); + } + + public Long getLong(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getLong(attributeName); + } + + public Long getLong(String attributeName, Long defaultValue) throws IllegalArgumentException { + return attributeAccessor.getLong(attributeName, defaultValue); + } + + public Long getRequiredLong(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getRequiredLong(attributeName); + } + + public Boolean getBoolean(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getBoolean(attributeName); + } + + public Boolean getBoolean(String attributeName, Boolean defaultValue) throws IllegalArgumentException { + return attributeAccessor.getBoolean(attributeName, defaultValue); + } + + public Boolean getRequiredBoolean(String attributeName) throws IllegalArgumentException { + return attributeAccessor.getRequiredBoolean(attributeName); + } + + public AttributeMap union(AttributeMap attributes) { + if (attributes == null) { + return new LocalAttributeMap<>(getMapInternal()); + } else { + Map map = createTargetMap(); + map.putAll(getMapInternal()); + map.putAll(attributes.asMap()); + return new LocalAttributeMap<>(map); + } + } + + // implementing MutableAttributeMap + + public V put(String attributeName, V attributeValue) { + return getMapInternal().put(attributeName, attributeValue); + } + + public MutableAttributeMap putAll(AttributeMap attributes) { + if (attributes == null) { + return this; + } + getMapInternal().putAll(attributes.asMap()); + return this; + } + + public MutableAttributeMap removeAll(MutableAttributeMap attributes) { + if (attributes == null) { + return this; + } + Map internal = getMapInternal(); + for (String attribute : attributes.asMap().keySet()) { + internal.remove(attribute); + } + return this; + } + + public Object remove(String attributeName) { + return getMapInternal().remove(attributeName); + } + + public Object extract(String attributeName) { + Map map = getMapInternal(); + if (map.containsKey(attributeName)) { + Object value = map.get(attributeName); + map.remove(attributeName); + return value; + } else { + return null; + } + } + + public MutableAttributeMap clear() throws UnsupportedOperationException { + getMapInternal().clear(); + return this; + } + + public MutableAttributeMap replaceWith(AttributeMap attributes) + throws UnsupportedOperationException { + clear(); + putAll(attributes); + return this; + } + + // helpers for subclasses + + /** + * Initializes this attribute map. + * @param attributes the attributes + */ + protected void initAttributes(Map attributes) { + this.attributes = attributes; + attributeAccessor = new MapAccessor<>(this.attributes); + } + + /** + * Returns the wrapped, modifiable map implementation. + */ + protected Map getMapInternal() { + return attributes; + } + + // helpers + + /** + * Factory method that returns the target map storing the data in this attribute map. + * @return the target map + */ + protected Map createTargetMap() { + return new HashMap<>(); + } + + /** + * Factory method that returns the target map storing the data in this attribute map. + * @param size the initial size of the map + * @param loadFactor the load factor + * @return the target map + */ + protected Map createTargetMap(int size, int loadFactor) { + return new HashMap<>(size, loadFactor); + } + + @SuppressWarnings("unchecked") + public boolean equals(Object o) { + if (!(o instanceof LocalAttributeMap)) { + return false; + } + LocalAttributeMap other = (LocalAttributeMap) o; + return getMapInternal().equals(other.getMapInternal()); + } + + public int hashCode() { + return getMapInternal().hashCode(); + } + + // custom serialization + + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + attributeAccessor = new MapAccessor<>(attributes); + } + + public String toString() { + return StylerUtils.style(attributes); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalParameterMap.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalParameterMap.java index 6d125158..a22d8d55 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalParameterMap.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalParameterMap.java @@ -1,323 +1,323 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.springframework.binding.collection.MapAccessor; -import org.springframework.binding.convert.ConversionExecutionException; -import org.springframework.binding.convert.ConversionExecutor; -import org.springframework.binding.convert.ConversionService; -import org.springframework.binding.convert.service.DefaultConversionService; -import org.springframework.core.style.StylerUtils; -import org.springframework.util.Assert; -import org.springframework.web.multipart.MultipartFile; - -/** - * An immutable parameter map storing String-keyed, String-valued parameters in a backing {@link Map} implementation. - * This base provides convenient operations for accessing parameters in a typed-manner. - * - * @author Keith Donald - */ -public class LocalParameterMap implements ParameterMap, Serializable { - - private static final DefaultConversionService DEFAULT_CONVERSION_SERVICE = new DefaultConversionService(); - - /** - * The backing map storing the parameters. - */ - private Map parameters; - - /** - * A helper for accessing parameters. Marked transient and restored on deserialization. - */ - private transient MapAccessor parameterAccessor; - - /** - * A helper for converting string parameter values. Marked transient and restored on deserialization. - */ - private transient ConversionService conversionService; - - /** - * Creates a new parameter map from the provided map. - *

- * It is expected that the contents of the backing map adhere to the parameter map contract; that is, map entries - * have string keys, string values, and remain unmodifiable. - * @param parameters the contents of this parameter map - */ - public LocalParameterMap(Map parameters) { - this(parameters, DEFAULT_CONVERSION_SERVICE); - } - - /** - * Creates a new parameter map from the provided map. - *

- * It is expected that the contents of the backing map adhere to the parameter map contract; that is, map entries - * have string keys, string values, and remain unmodifiable. - * @param parameters the contents of this parameter map - * @param conversionService a helper for performing type conversion of map entry values - */ - public LocalParameterMap(Map parameters, ConversionService conversionService) { - initParameters(parameters); - this.conversionService = conversionService; - } - - public boolean equals(Object o) { - if (!(o instanceof LocalParameterMap)) { - return false; - } - LocalParameterMap other = (LocalParameterMap) o; - return parameters.equals(other.parameters); - } - - public int hashCode() { - return parameters.hashCode(); - } - - public Map asMap() { - return Collections.unmodifiableMap(parameterAccessor.asMap()); - } - - public boolean isEmpty() { - return parameters.isEmpty(); - } - - public int size() { - return parameters.size(); - } - - public boolean contains(String parameterName) { - return parameters.containsKey(parameterName); - } - - public String get(String parameterName) { - return get(parameterName, (String) null); - } - - public String get(String parameterName, String defaultValue) { - if (!parameters.containsKey(parameterName)) { - return defaultValue; - } - Object value = parameters.get(parameterName); - if (value.getClass().isArray()) { - parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String[].class); - String[] array = (String[]) value; - if (array.length == 0) { - return null; - } else { - Object first = ((String[]) value)[0]; - parameterAccessor.assertKeyValueInstanceOf(parameterName, first, String.class); - return (String) first; - } - - } else { - parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String.class); - return (String) value; - } - } - - public String[] getArray(String parameterName) { - if (!parameters.containsKey(parameterName)) { - return null; - } - Object value = parameters.get(parameterName); - if (value.getClass().isArray()) { - parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String[].class); - return (String[]) value; - } else { - parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String.class); - return new String[] { (String) value }; - } - } - - public T[] getArray(String parameterName, Class targetElementType) throws ConversionExecutionException { - String[] parameters = getArray(parameterName); - return parameters != null ? convert(parameters, targetElementType) : null; - } - - public T get(String parameterName, Class targetType) throws ConversionExecutionException { - return get(parameterName, targetType, null); - } - - public T get(String parameterName, Class targetType, T defaultValue) throws ConversionExecutionException { - if (defaultValue != null) { - assertAssignableTo(targetType, defaultValue.getClass()); - } - String parameter = get(parameterName); - return parameter != null ? convert(parameter, targetType) : defaultValue; - } - - public String getRequired(String parameterName) throws IllegalArgumentException { - parameterAccessor.assertContainsKey(parameterName); - return get(parameterName); - } - - public String[] getRequiredArray(String parameterName) throws IllegalArgumentException { - parameterAccessor.assertContainsKey(parameterName); - return getArray(parameterName); - } - - public T[] getRequiredArray(String parameterName, Class targetElementType) throws IllegalArgumentException, - ConversionExecutionException { - String[] parameters = getRequiredArray(parameterName); - return convert(parameters, targetElementType); - } - - public T getRequired(String parameterName, Class targetType) throws IllegalArgumentException, - ConversionExecutionException { - return convert(getRequired(parameterName), targetType); - } - - public T getNumber(String parameterName, Class targetType) - throws ConversionExecutionException { - assertAssignableTo(Number.class, targetType); - return get(parameterName, targetType); - } - - public T getNumber(String parameterName, Class targetType, T defaultValue) - throws ConversionExecutionException { - assertAssignableTo(Number.class, targetType); - return get(parameterName, targetType, defaultValue); - } - - public T getRequiredNumber(String parameterName, Class targetType) - throws IllegalArgumentException, ConversionExecutionException { - assertAssignableTo(Number.class, targetType); - return getRequired(parameterName, targetType); - } - - public Integer getInteger(String parameterName) throws ConversionExecutionException { - return get(parameterName, Integer.class); - } - - public Integer getInteger(String parameterName, Integer defaultValue) throws ConversionExecutionException { - return get(parameterName, Integer.class, defaultValue); - } - - public Integer getRequiredInteger(String parameterName) throws IllegalArgumentException, - ConversionExecutionException { - return getRequired(parameterName, Integer.class); - } - - public Long getLong(String parameterName) throws ConversionExecutionException { - return get(parameterName, Long.class); - } - - public Long getLong(String parameterName, Long defaultValue) throws ConversionExecutionException { - return get(parameterName, Long.class, defaultValue); - } - - public Long getRequiredLong(String parameterName) throws IllegalArgumentException, ConversionExecutionException { - return getRequired(parameterName, Long.class); - } - - public Boolean getBoolean(String parameterName) throws ConversionExecutionException { - return get(parameterName, Boolean.class); - } - - public Boolean getBoolean(String parameterName, Boolean defaultValue) throws ConversionExecutionException { - return get(parameterName, Boolean.class, defaultValue); - } - - public Boolean getRequiredBoolean(String parameterName) throws IllegalArgumentException, - ConversionExecutionException { - return getRequired(parameterName, Boolean.class); - } - - public MultipartFile getMultipartFile(String parameterName) { - return parameterAccessor.get(parameterName, MultipartFile.class); - } - - public MultipartFile getRequiredMultipartFile(String parameterName) throws IllegalArgumentException { - return parameterAccessor.getRequired(parameterName, MultipartFile.class); - } - - public AttributeMap asAttributeMap() { - return new LocalAttributeMap<>(getMapInternal()); - } - - /** - * Initializes this parameter map. - * @param parameters the parameters - */ - protected void initParameters(Map parameters) { - this.parameters = parameters; - parameterAccessor = new MapAccessor<>(this.parameters); - } - - /** - * Returns the wrapped, modifiable map implementation. - */ - protected Map getMapInternal() { - return parameters; - } - - // internal helpers - - /** - * Convert given String parameter to specified target type. - */ - @SuppressWarnings("unchecked") - private T convert(String parameter, Class targetType) throws ConversionExecutionException { - return (T) conversionService.getConversionExecutor(String.class, targetType).execute(parameter); - } - - /** - * Convert given array of String parameters to specified target type and return the resulting array. - */ - @SuppressWarnings("unchecked") - private T[] convert(String[] parameters, Class targetElementType) - throws ConversionExecutionException { - List list = new ArrayList<>(parameters.length); - ConversionExecutor converter = conversionService.getConversionExecutor(String.class, targetElementType); - for (String parameter : parameters) { - list.add((T) converter.execute(parameter)); - } - return list.toArray((T[]) Array.newInstance(targetElementType, parameters.length)); - } - - /** - * Make sure clazz is assignable from requiredType. - */ - private void assertAssignableTo(Class clazz, Class requiredType) { - Assert.isTrue(clazz.isAssignableFrom(requiredType), "The provided required type must be assignable to [" - + clazz + "]"); - } - - // custom serialization - - private void writeObject(ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - parameterAccessor = new MapAccessor<>(parameters); - conversionService = DEFAULT_CONVERSION_SERVICE; - } - - public String toString() { - return StylerUtils.style(parameters); - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.springframework.binding.collection.MapAccessor; +import org.springframework.binding.convert.ConversionExecutionException; +import org.springframework.binding.convert.ConversionExecutor; +import org.springframework.binding.convert.ConversionService; +import org.springframework.binding.convert.service.DefaultConversionService; +import org.springframework.core.style.StylerUtils; +import org.springframework.util.Assert; +import org.springframework.web.multipart.MultipartFile; + +/** + * An immutable parameter map storing String-keyed, String-valued parameters in a backing {@link Map} implementation. + * This base provides convenient operations for accessing parameters in a typed-manner. + * + * @author Keith Donald + */ +public class LocalParameterMap implements ParameterMap, Serializable { + + private static final DefaultConversionService DEFAULT_CONVERSION_SERVICE = new DefaultConversionService(); + + /** + * The backing map storing the parameters. + */ + private Map parameters; + + /** + * A helper for accessing parameters. Marked transient and restored on deserialization. + */ + private transient MapAccessor parameterAccessor; + + /** + * A helper for converting string parameter values. Marked transient and restored on deserialization. + */ + private transient ConversionService conversionService; + + /** + * Creates a new parameter map from the provided map. + *

+ * It is expected that the contents of the backing map adhere to the parameter map contract; that is, map entries + * have string keys, string values, and remain unmodifiable. + * @param parameters the contents of this parameter map + */ + public LocalParameterMap(Map parameters) { + this(parameters, DEFAULT_CONVERSION_SERVICE); + } + + /** + * Creates a new parameter map from the provided map. + *

+ * It is expected that the contents of the backing map adhere to the parameter map contract; that is, map entries + * have string keys, string values, and remain unmodifiable. + * @param parameters the contents of this parameter map + * @param conversionService a helper for performing type conversion of map entry values + */ + public LocalParameterMap(Map parameters, ConversionService conversionService) { + initParameters(parameters); + this.conversionService = conversionService; + } + + public boolean equals(Object o) { + if (!(o instanceof LocalParameterMap)) { + return false; + } + LocalParameterMap other = (LocalParameterMap) o; + return parameters.equals(other.parameters); + } + + public int hashCode() { + return parameters.hashCode(); + } + + public Map asMap() { + return Collections.unmodifiableMap(parameterAccessor.asMap()); + } + + public boolean isEmpty() { + return parameters.isEmpty(); + } + + public int size() { + return parameters.size(); + } + + public boolean contains(String parameterName) { + return parameters.containsKey(parameterName); + } + + public String get(String parameterName) { + return get(parameterName, (String) null); + } + + public String get(String parameterName, String defaultValue) { + if (!parameters.containsKey(parameterName)) { + return defaultValue; + } + Object value = parameters.get(parameterName); + if (value.getClass().isArray()) { + parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String[].class); + String[] array = (String[]) value; + if (array.length == 0) { + return null; + } else { + Object first = ((String[]) value)[0]; + parameterAccessor.assertKeyValueInstanceOf(parameterName, first, String.class); + return (String) first; + } + + } else { + parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String.class); + return (String) value; + } + } + + public String[] getArray(String parameterName) { + if (!parameters.containsKey(parameterName)) { + return null; + } + Object value = parameters.get(parameterName); + if (value.getClass().isArray()) { + parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String[].class); + return (String[]) value; + } else { + parameterAccessor.assertKeyValueInstanceOf(parameterName, value, String.class); + return new String[] { (String) value }; + } + } + + public T[] getArray(String parameterName, Class targetElementType) throws ConversionExecutionException { + String[] parameters = getArray(parameterName); + return parameters != null ? convert(parameters, targetElementType) : null; + } + + public T get(String parameterName, Class targetType) throws ConversionExecutionException { + return get(parameterName, targetType, null); + } + + public T get(String parameterName, Class targetType, T defaultValue) throws ConversionExecutionException { + if (defaultValue != null) { + assertAssignableTo(targetType, defaultValue.getClass()); + } + String parameter = get(parameterName); + return parameter != null ? convert(parameter, targetType) : defaultValue; + } + + public String getRequired(String parameterName) throws IllegalArgumentException { + parameterAccessor.assertContainsKey(parameterName); + return get(parameterName); + } + + public String[] getRequiredArray(String parameterName) throws IllegalArgumentException { + parameterAccessor.assertContainsKey(parameterName); + return getArray(parameterName); + } + + public T[] getRequiredArray(String parameterName, Class targetElementType) throws IllegalArgumentException, + ConversionExecutionException { + String[] parameters = getRequiredArray(parameterName); + return convert(parameters, targetElementType); + } + + public T getRequired(String parameterName, Class targetType) throws IllegalArgumentException, + ConversionExecutionException { + return convert(getRequired(parameterName), targetType); + } + + public T getNumber(String parameterName, Class targetType) + throws ConversionExecutionException { + assertAssignableTo(Number.class, targetType); + return get(parameterName, targetType); + } + + public T getNumber(String parameterName, Class targetType, T defaultValue) + throws ConversionExecutionException { + assertAssignableTo(Number.class, targetType); + return get(parameterName, targetType, defaultValue); + } + + public T getRequiredNumber(String parameterName, Class targetType) + throws IllegalArgumentException, ConversionExecutionException { + assertAssignableTo(Number.class, targetType); + return getRequired(parameterName, targetType); + } + + public Integer getInteger(String parameterName) throws ConversionExecutionException { + return get(parameterName, Integer.class); + } + + public Integer getInteger(String parameterName, Integer defaultValue) throws ConversionExecutionException { + return get(parameterName, Integer.class, defaultValue); + } + + public Integer getRequiredInteger(String parameterName) throws IllegalArgumentException, + ConversionExecutionException { + return getRequired(parameterName, Integer.class); + } + + public Long getLong(String parameterName) throws ConversionExecutionException { + return get(parameterName, Long.class); + } + + public Long getLong(String parameterName, Long defaultValue) throws ConversionExecutionException { + return get(parameterName, Long.class, defaultValue); + } + + public Long getRequiredLong(String parameterName) throws IllegalArgumentException, ConversionExecutionException { + return getRequired(parameterName, Long.class); + } + + public Boolean getBoolean(String parameterName) throws ConversionExecutionException { + return get(parameterName, Boolean.class); + } + + public Boolean getBoolean(String parameterName, Boolean defaultValue) throws ConversionExecutionException { + return get(parameterName, Boolean.class, defaultValue); + } + + public Boolean getRequiredBoolean(String parameterName) throws IllegalArgumentException, + ConversionExecutionException { + return getRequired(parameterName, Boolean.class); + } + + public MultipartFile getMultipartFile(String parameterName) { + return parameterAccessor.get(parameterName, MultipartFile.class); + } + + public MultipartFile getRequiredMultipartFile(String parameterName) throws IllegalArgumentException { + return parameterAccessor.getRequired(parameterName, MultipartFile.class); + } + + public AttributeMap asAttributeMap() { + return new LocalAttributeMap<>(getMapInternal()); + } + + /** + * Initializes this parameter map. + * @param parameters the parameters + */ + protected void initParameters(Map parameters) { + this.parameters = parameters; + parameterAccessor = new MapAccessor<>(this.parameters); + } + + /** + * Returns the wrapped, modifiable map implementation. + */ + protected Map getMapInternal() { + return parameters; + } + + // internal helpers + + /** + * Convert given String parameter to specified target type. + */ + @SuppressWarnings("unchecked") + private T convert(String parameter, Class targetType) throws ConversionExecutionException { + return (T) conversionService.getConversionExecutor(String.class, targetType).execute(parameter); + } + + /** + * Convert given array of String parameters to specified target type and return the resulting array. + */ + @SuppressWarnings("unchecked") + private T[] convert(String[] parameters, Class targetElementType) + throws ConversionExecutionException { + List list = new ArrayList<>(parameters.length); + ConversionExecutor converter = conversionService.getConversionExecutor(String.class, targetElementType); + for (String parameter : parameters) { + list.add((T) converter.execute(parameter)); + } + return list.toArray((T[]) Array.newInstance(targetElementType, parameters.length)); + } + + /** + * Make sure clazz is assignable from requiredType. + */ + private void assertAssignableTo(Class clazz, Class requiredType) { + Assert.isTrue(clazz.isAssignableFrom(requiredType), "The provided required type must be assignable to [" + + clazz + "]"); + } + + // custom serialization + + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + parameterAccessor = new MapAccessor<>(parameters); + conversionService = DEFAULT_CONVERSION_SERVICE; + } + + public String toString() { + return StylerUtils.style(parameters); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalSharedAttributeMap.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalSharedAttributeMap.java index ed0b2435..426866c8 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalSharedAttributeMap.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/LocalSharedAttributeMap.java @@ -1,48 +1,48 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -import org.springframework.binding.collection.SharedMap; - -/** - * An attribute map that exposes a mutex that application code can synchronize on. This class wraps another shared map - * in an attribute map. - *

- * The mutex can be used to serialize concurrent access to the shared map's contents by multiple threads. - * - * @author Keith Donald - */ -public class LocalSharedAttributeMap extends LocalAttributeMap implements SharedAttributeMap { - - /** - * Creates a new shared attribute map. - * @param sharedMap the shared map - */ - public LocalSharedAttributeMap(SharedMap sharedMap) { - super(sharedMap); - } - - public Object getMutex() { - return getSharedMap().getMutex(); - } - - /** - * Returns the wrapped shared map. - */ - protected SharedMap getSharedMap() { - return (SharedMap) getMapInternal(); - } +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +import org.springframework.binding.collection.SharedMap; + +/** + * An attribute map that exposes a mutex that application code can synchronize on. This class wraps another shared map + * in an attribute map. + *

+ * The mutex can be used to serialize concurrent access to the shared map's contents by multiple threads. + * + * @author Keith Donald + */ +public class LocalSharedAttributeMap extends LocalAttributeMap implements SharedAttributeMap { + + /** + * Creates a new shared attribute map. + * @param sharedMap the shared map + */ + public LocalSharedAttributeMap(SharedMap sharedMap) { + super(sharedMap); + } + + public Object getMutex() { + return getSharedMap().getMutex(); + } + + /** + * Returns the wrapped shared map. + */ + protected SharedMap getSharedMap() { + return (SharedMap) getMapInternal(); + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/MutableAttributeMap.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/MutableAttributeMap.java index d7a2d83c..3eeef053 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/MutableAttributeMap.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/MutableAttributeMap.java @@ -1,84 +1,84 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -/** - * An interface for accessing and modifying attributes in a backing map with string keys. - *

- * Implementations can optionally support {@link AttributeMapBindingListener listeners} that will be notified when - * they're bound in or unbound from the map. - * - * @author Keith Donald - */ -public interface MutableAttributeMap extends AttributeMap { - - /** - * Put the attribute into this map. - *

- * If the attribute value is an {@link AttributeMapBindingListener} this map will publish - * {@link AttributeMapBindingEvent binding events} such as on "bind" and "unbind" if supported. - *

- * Note: not all MutableAttributeMap implementations support this. - * @param attributeName the attribute name - * @param attributeValue the attribute value - * @return the previous value of the attribute, or null of there was no previous value - */ - V put(String attributeName, V attributeValue); - - /** - * Put all the attributes into this map. - * @param attributes the attributes to put into this map - * @return this, to support call chaining - */ - MutableAttributeMap putAll(AttributeMap attributes); - - /** - * Remove all attributes in the map provided from this map. - * @param attributes the attributes to remove from this map - * @return this, to support call chaining - */ - MutableAttributeMap removeAll(MutableAttributeMap attributes); - - /** - * Remove an attribute from this map. - * @param attributeName the name of the attribute to remove - * @return previous value associated with specified attribute name, or null if there was no mapping for the - * name - */ - Object remove(String attributeName); - - /** - * Extract an attribute from this map, getting it and removing it in a single operation. - * @param attributeName the attribute name - * @return the value of the attribute, or null of there was no value - */ - Object extract(String attributeName); - - /** - * Remove all attributes in this map. - * @return this, to support call chaining - */ - MutableAttributeMap clear(); - - /** - * Replace the contents of this attribute map with the contents of the provided collection. - * @param attributes the attribute collection - * @return this, to support call chaining - */ - MutableAttributeMap replaceWith(AttributeMap attributes) - throws UnsupportedOperationException; - -} +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +/** + * An interface for accessing and modifying attributes in a backing map with string keys. + *

+ * Implementations can optionally support {@link AttributeMapBindingListener listeners} that will be notified when + * they're bound in or unbound from the map. + * + * @author Keith Donald + */ +public interface MutableAttributeMap extends AttributeMap { + + /** + * Put the attribute into this map. + *

+ * If the attribute value is an {@link AttributeMapBindingListener} this map will publish + * {@link AttributeMapBindingEvent binding events} such as on "bind" and "unbind" if supported. + *

+ * Note: not all MutableAttributeMap implementations support this. + * @param attributeName the attribute name + * @param attributeValue the attribute value + * @return the previous value of the attribute, or null of there was no previous value + */ + V put(String attributeName, V attributeValue); + + /** + * Put all the attributes into this map. + * @param attributes the attributes to put into this map + * @return this, to support call chaining + */ + MutableAttributeMap putAll(AttributeMap attributes); + + /** + * Remove all attributes in the map provided from this map. + * @param attributes the attributes to remove from this map + * @return this, to support call chaining + */ + MutableAttributeMap removeAll(MutableAttributeMap attributes); + + /** + * Remove an attribute from this map. + * @param attributeName the name of the attribute to remove + * @return previous value associated with specified attribute name, or null if there was no mapping for the + * name + */ + Object remove(String attributeName); + + /** + * Extract an attribute from this map, getting it and removing it in a single operation. + * @param attributeName the attribute name + * @return the value of the attribute, or null of there was no value + */ + Object extract(String attributeName); + + /** + * Remove all attributes in this map. + * @return this, to support call chaining + */ + MutableAttributeMap clear(); + + /** + * Replace the contents of this attribute map with the contents of the provided collection. + * @param attributes the attribute collection + * @return this, to support call chaining + */ + MutableAttributeMap replaceWith(AttributeMap attributes) + throws UnsupportedOperationException; + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/ParameterMap.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/ParameterMap.java index a51b95fd..27466d32 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/ParameterMap.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/ParameterMap.java @@ -1,279 +1,279 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -import org.springframework.binding.collection.MapAdaptable; -import org.springframework.binding.convert.ConversionExecutionException; -import org.springframework.web.multipart.MultipartFile; - -/** - * An interface for accessing parameters in a backing map. Parameters are immutable and have string keys and string - * values. - *

- * The accessor methods offered by this class taking a target type argument only need to support conversions to well - * know types like String, Number subclasses, Boolean and so on. - * - * @author Keith Donald - */ -public interface ParameterMap extends MapAdaptable { - - /** - * Is this parameter map empty, with a size of 0? - * @return true if empty, false if not - */ - boolean isEmpty(); - - /** - * Returns the number of parameters in this map. - * @return the parameter count - */ - int size(); - - /** - * Does the parameter with the provided name exist in this map? - * @param parameterName the parameter name - * @return true if so, false otherwise - */ - boolean contains(String parameterName); - - /** - * Get a parameter value, returning null if no value is found. - * @param parameterName the parameter name - * @return the parameter value - */ - String get(String parameterName); - - /** - * Get a parameter value, returning the defaultValue if no value is found. - * @param parameterName the parameter name - * @param defaultValue the default - * @return the parameter value - */ - String get(String parameterName, String defaultValue); - - /** - * Get a multi-valued parameter value, returning null if no value is found. If the parameter is single - * valued an array with a single element is returned. - * @param parameterName the parameter name - * @return the parameter value array - */ - String[] getArray(String parameterName); - - /** - * Get a multi-valued parameter value, converting each value to the target type or returning null if no - * value is found. - * @param parameterName the parameter name - * @param targetElementType the target type of the array's elements - * @return the converterd parameter value array - * @throws ConversionExecutionException when the value could not be converted - */ - T[] getArray(String parameterName, Class targetElementType) throws ConversionExecutionException; - - /** - * Get a parameter value, converting it from String to the target type. - * @param parameterName the name of the parameter - * @param targetType the target type of the parameter value - * @return the converted parameter value, or null if not found - * @throws ConversionExecutionException when the value could not be converted - */ - T get(String parameterName, Class targetType) throws ConversionExecutionException; - - /** - * Get a parameter value, converting it from String to the target type or returning the defaultValue if - * not found. - * @param parameterName name of the parameter to get - * @param targetType the target type of the parameter value - * @param defaultValue the default value - * @return the converted parameter value, or the default if not found - * @throws ConversionExecutionException when a value could not be converted - */ - T get(String parameterName, Class targetType, T defaultValue) throws ConversionExecutionException; - - /** - * Get the value of a required parameter. - * @param parameterName the name of the parameter - * @return the parameter value - * @throws IllegalArgumentException when the parameter is not found - */ - String getRequired(String parameterName) throws IllegalArgumentException; - - /** - * Get a required multi-valued parameter value. - * @param parameterName the name of the parameter - * @return the parameter value - * @throws IllegalArgumentException when the parameter is not found - */ - String[] getRequiredArray(String parameterName) throws IllegalArgumentException; - - /** - * Get a required multi-valued parameter value, converting each value to the target type. - * @param parameterName the name of the parameter - * @return the parameter value - * @throws IllegalArgumentException when the parameter is not found - * @throws ConversionExecutionException when a value could not be converted - */ - T[] getRequiredArray(String parameterName, Class targetElementType) throws IllegalArgumentException, - ConversionExecutionException; - - /** - * Get the value of a required parameter and convert it to the target type. - * @param parameterName the name of the parameter - * @param targetType the target type of the parameter value - * @return the converted parameter value - * @throws IllegalArgumentException when the parameter is not found - * @throws ConversionExecutionException when the value could not be converted - */ - T getRequired(String parameterName, Class targetType) throws IllegalArgumentException, - ConversionExecutionException; - - /** - * Returns a number parameter value in the map that is of the specified type, returning null if no - * value was found. - * @param parameterName the parameter name - * @param targetType the target number type - * @return the number parameter value - * @throws ConversionExecutionException when the value could not be converted - */ - T getNumber(String parameterName, Class targetType) - throws ConversionExecutionException; - - /** - * Returns a number parameter value in the map of the specified type, returning the defaultValue if no value was - * found. - * @param parameterName the parameter name - * @param defaultValue the default - * @return the number parameter value - * @throws ConversionExecutionException when the value could not be converted - */ - T getNumber(String parameterName, Class targetType, T defaultValue) - throws ConversionExecutionException; - - /** - * Returns a number parameter value in the map, throwing an exception if the parameter is not present or could not - * be converted. - * @param parameterName the parameter name - * @return the number parameter value - * @throws IllegalArgumentException if the parameter is not present - * @throws ConversionExecutionException when the value could not be converted - */ - T getRequiredNumber(String parameterName, Class targetType) - throws IllegalArgumentException, ConversionExecutionException; - - /** - * Returns an integer parameter value in the map, returning null if no value was found. - * @param parameterName the parameter name - * @return the integer parameter value - * @throws ConversionExecutionException when the value could not be converted - */ - Integer getInteger(String parameterName) throws ConversionExecutionException; - - /** - * Returns an integer parameter value in the map, returning the defaultValue if no value was found. - * @param parameterName the parameter name - * @param defaultValue the default - * @return the integer parameter value - * @throws ConversionExecutionException when the value could not be converted - */ - Integer getInteger(String parameterName, Integer defaultValue) throws ConversionExecutionException; - - /** - * Returns an integer parameter value in the map, throwing an exception if the parameter is not present or could not - * be converted. - * @param parameterName the parameter name - * @return the integer parameter value - * @throws IllegalArgumentException if the parameter is not present - * @throws ConversionExecutionException when the value could not be converted - */ - Integer getRequiredInteger(String parameterName) throws IllegalArgumentException, - ConversionExecutionException; - - /** - * Returns a long parameter value in the map, returning null if no value was found. - * @param parameterName the parameter name - * @return the long parameter value - * @throws ConversionExecutionException when the value could not be converted - */ - Long getLong(String parameterName) throws ConversionExecutionException; - - /** - * Returns a long parameter value in the map, returning the defaultValue if no value was found. - * @param parameterName the parameter name - * @param defaultValue the default - * @return the long parameter value - * @throws ConversionExecutionException when the value could not be converted - */ - Long getLong(String parameterName, Long defaultValue) throws ConversionExecutionException; - - /** - * Returns a long parameter value in the map, throwing an exception if the parameter is not present or could not be - * converted. - * @param parameterName the parameter name - * @return the long parameter value - * @throws IllegalArgumentException if the parameter is not present - * @throws ConversionExecutionException when the value could not be converted - */ - Long getRequiredLong(String parameterName) throws IllegalArgumentException, ConversionExecutionException; - - /** - * Returns a boolean parameter value in the map, returning null if no value was found. - * @param parameterName the parameter name - * @return the long parameter value - * @throws ConversionExecutionException when the value could not be converted - */ - Boolean getBoolean(String parameterName) throws ConversionExecutionException; - - /** - * Returns a boolean parameter value in the map, returning the defaultValue if no value was found. - * @param parameterName the parameter name - * @param defaultValue the default - * @return the boolean parameter value - * @throws ConversionExecutionException when the value could not be converted - */ - Boolean getBoolean(String parameterName, Boolean defaultValue) throws ConversionExecutionException; - - /** - * Returns a boolean parameter value in the map, throwing an exception if the parameter is not present or could not - * be converted. - * @param parameterName the parameter name - * @return the boolean parameter value - * @throws IllegalArgumentException if the parameter is not present - * @throws ConversionExecutionException when the value could not be converted - */ - Boolean getRequiredBoolean(String parameterName) throws IllegalArgumentException, - ConversionExecutionException; - - /** - * Get a multi-part file parameter value, returning null if no value is found. - * @param parameterName the parameter name - * @return the multipart file - */ - MultipartFile getMultipartFile(String parameterName); - - /** - * Get the value of a required multipart file parameter. - * @param parameterName the name of the parameter - * @return the parameter value - * @throws IllegalArgumentException when the parameter is not found - */ - MultipartFile getRequiredMultipartFile(String parameterName); - - /** - * Adapts this parameter map to an {@link AttributeMap}. - * @return the underlying map as a unmodifiable attribute map - */ - AttributeMap asAttributeMap(); - -} +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +import org.springframework.binding.collection.MapAdaptable; +import org.springframework.binding.convert.ConversionExecutionException; +import org.springframework.web.multipart.MultipartFile; + +/** + * An interface for accessing parameters in a backing map. Parameters are immutable and have string keys and string + * values. + *

+ * The accessor methods offered by this class taking a target type argument only need to support conversions to well + * know types like String, Number subclasses, Boolean and so on. + * + * @author Keith Donald + */ +public interface ParameterMap extends MapAdaptable { + + /** + * Is this parameter map empty, with a size of 0? + * @return true if empty, false if not + */ + boolean isEmpty(); + + /** + * Returns the number of parameters in this map. + * @return the parameter count + */ + int size(); + + /** + * Does the parameter with the provided name exist in this map? + * @param parameterName the parameter name + * @return true if so, false otherwise + */ + boolean contains(String parameterName); + + /** + * Get a parameter value, returning null if no value is found. + * @param parameterName the parameter name + * @return the parameter value + */ + String get(String parameterName); + + /** + * Get a parameter value, returning the defaultValue if no value is found. + * @param parameterName the parameter name + * @param defaultValue the default + * @return the parameter value + */ + String get(String parameterName, String defaultValue); + + /** + * Get a multi-valued parameter value, returning null if no value is found. If the parameter is single + * valued an array with a single element is returned. + * @param parameterName the parameter name + * @return the parameter value array + */ + String[] getArray(String parameterName); + + /** + * Get a multi-valued parameter value, converting each value to the target type or returning null if no + * value is found. + * @param parameterName the parameter name + * @param targetElementType the target type of the array's elements + * @return the converterd parameter value array + * @throws ConversionExecutionException when the value could not be converted + */ + T[] getArray(String parameterName, Class targetElementType) throws ConversionExecutionException; + + /** + * Get a parameter value, converting it from String to the target type. + * @param parameterName the name of the parameter + * @param targetType the target type of the parameter value + * @return the converted parameter value, or null if not found + * @throws ConversionExecutionException when the value could not be converted + */ + T get(String parameterName, Class targetType) throws ConversionExecutionException; + + /** + * Get a parameter value, converting it from String to the target type or returning the defaultValue if + * not found. + * @param parameterName name of the parameter to get + * @param targetType the target type of the parameter value + * @param defaultValue the default value + * @return the converted parameter value, or the default if not found + * @throws ConversionExecutionException when a value could not be converted + */ + T get(String parameterName, Class targetType, T defaultValue) throws ConversionExecutionException; + + /** + * Get the value of a required parameter. + * @param parameterName the name of the parameter + * @return the parameter value + * @throws IllegalArgumentException when the parameter is not found + */ + String getRequired(String parameterName) throws IllegalArgumentException; + + /** + * Get a required multi-valued parameter value. + * @param parameterName the name of the parameter + * @return the parameter value + * @throws IllegalArgumentException when the parameter is not found + */ + String[] getRequiredArray(String parameterName) throws IllegalArgumentException; + + /** + * Get a required multi-valued parameter value, converting each value to the target type. + * @param parameterName the name of the parameter + * @return the parameter value + * @throws IllegalArgumentException when the parameter is not found + * @throws ConversionExecutionException when a value could not be converted + */ + T[] getRequiredArray(String parameterName, Class targetElementType) throws IllegalArgumentException, + ConversionExecutionException; + + /** + * Get the value of a required parameter and convert it to the target type. + * @param parameterName the name of the parameter + * @param targetType the target type of the parameter value + * @return the converted parameter value + * @throws IllegalArgumentException when the parameter is not found + * @throws ConversionExecutionException when the value could not be converted + */ + T getRequired(String parameterName, Class targetType) throws IllegalArgumentException, + ConversionExecutionException; + + /** + * Returns a number parameter value in the map that is of the specified type, returning null if no + * value was found. + * @param parameterName the parameter name + * @param targetType the target number type + * @return the number parameter value + * @throws ConversionExecutionException when the value could not be converted + */ + T getNumber(String parameterName, Class targetType) + throws ConversionExecutionException; + + /** + * Returns a number parameter value in the map of the specified type, returning the defaultValue if no value was + * found. + * @param parameterName the parameter name + * @param defaultValue the default + * @return the number parameter value + * @throws ConversionExecutionException when the value could not be converted + */ + T getNumber(String parameterName, Class targetType, T defaultValue) + throws ConversionExecutionException; + + /** + * Returns a number parameter value in the map, throwing an exception if the parameter is not present or could not + * be converted. + * @param parameterName the parameter name + * @return the number parameter value + * @throws IllegalArgumentException if the parameter is not present + * @throws ConversionExecutionException when the value could not be converted + */ + T getRequiredNumber(String parameterName, Class targetType) + throws IllegalArgumentException, ConversionExecutionException; + + /** + * Returns an integer parameter value in the map, returning null if no value was found. + * @param parameterName the parameter name + * @return the integer parameter value + * @throws ConversionExecutionException when the value could not be converted + */ + Integer getInteger(String parameterName) throws ConversionExecutionException; + + /** + * Returns an integer parameter value in the map, returning the defaultValue if no value was found. + * @param parameterName the parameter name + * @param defaultValue the default + * @return the integer parameter value + * @throws ConversionExecutionException when the value could not be converted + */ + Integer getInteger(String parameterName, Integer defaultValue) throws ConversionExecutionException; + + /** + * Returns an integer parameter value in the map, throwing an exception if the parameter is not present or could not + * be converted. + * @param parameterName the parameter name + * @return the integer parameter value + * @throws IllegalArgumentException if the parameter is not present + * @throws ConversionExecutionException when the value could not be converted + */ + Integer getRequiredInteger(String parameterName) throws IllegalArgumentException, + ConversionExecutionException; + + /** + * Returns a long parameter value in the map, returning null if no value was found. + * @param parameterName the parameter name + * @return the long parameter value + * @throws ConversionExecutionException when the value could not be converted + */ + Long getLong(String parameterName) throws ConversionExecutionException; + + /** + * Returns a long parameter value in the map, returning the defaultValue if no value was found. + * @param parameterName the parameter name + * @param defaultValue the default + * @return the long parameter value + * @throws ConversionExecutionException when the value could not be converted + */ + Long getLong(String parameterName, Long defaultValue) throws ConversionExecutionException; + + /** + * Returns a long parameter value in the map, throwing an exception if the parameter is not present or could not be + * converted. + * @param parameterName the parameter name + * @return the long parameter value + * @throws IllegalArgumentException if the parameter is not present + * @throws ConversionExecutionException when the value could not be converted + */ + Long getRequiredLong(String parameterName) throws IllegalArgumentException, ConversionExecutionException; + + /** + * Returns a boolean parameter value in the map, returning null if no value was found. + * @param parameterName the parameter name + * @return the long parameter value + * @throws ConversionExecutionException when the value could not be converted + */ + Boolean getBoolean(String parameterName) throws ConversionExecutionException; + + /** + * Returns a boolean parameter value in the map, returning the defaultValue if no value was found. + * @param parameterName the parameter name + * @param defaultValue the default + * @return the boolean parameter value + * @throws ConversionExecutionException when the value could not be converted + */ + Boolean getBoolean(String parameterName, Boolean defaultValue) throws ConversionExecutionException; + + /** + * Returns a boolean parameter value in the map, throwing an exception if the parameter is not present or could not + * be converted. + * @param parameterName the parameter name + * @return the boolean parameter value + * @throws IllegalArgumentException if the parameter is not present + * @throws ConversionExecutionException when the value could not be converted + */ + Boolean getRequiredBoolean(String parameterName) throws IllegalArgumentException, + ConversionExecutionException; + + /** + * Get a multi-part file parameter value, returning null if no value is found. + * @param parameterName the parameter name + * @return the multipart file + */ + MultipartFile getMultipartFile(String parameterName); + + /** + * Get the value of a required multipart file parameter. + * @param parameterName the name of the parameter + * @return the parameter value + * @throws IllegalArgumentException when the parameter is not found + */ + MultipartFile getRequiredMultipartFile(String parameterName); + + /** + * Adapts this parameter map to an {@link AttributeMap}. + * @return the underlying map as a unmodifiable attribute map + */ + AttributeMap asAttributeMap(); + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/SharedAttributeMap.java b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/SharedAttributeMap.java index b9cfaa28..8811cb33 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/core/collection/SharedAttributeMap.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/core/collection/SharedAttributeMap.java @@ -1,29 +1,29 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -/** - * An interface to be implemented by mutable attribute maps accessed by multiple threads that need to be synchronized. - * - * @author Keith Donald - */ -public interface SharedAttributeMap extends MutableAttributeMap { - - /** - * Returns the shared map's mutex, which may be synchronized on to block access to the map by other threads. - */ - Object getMutex(); -} +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +/** + * An interface to be implemented by mutable attribute maps accessed by multiple threads that need to be synchronized. + * + * @author Keith Donald + */ +public interface SharedAttributeMap extends MutableAttributeMap { + + /** + * Returns the shared map's mutex, which may be synchronized on to block access to the map by other threads. + */ + Object getMutex(); +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/definition/FlowDefinition.java b/spring-webflow/src/main/java/org/springframework/webflow/definition/FlowDefinition.java index cd19d4b8..a9009276 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/definition/FlowDefinition.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/definition/FlowDefinition.java @@ -1,95 +1,95 @@ -/* - * 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 - * - * https://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.definition; - -import org.springframework.context.ApplicationContext; -import org.springframework.webflow.core.Annotated; - -/** - * The definition of a flow, a program that when executed carries out a task on behalf of a single client. - *

- * A flow definition is a reusable, self-contained controller module that defines a blue print for an executable user - * task. Flows typically orchestrate controlled navigations or dialogs within web applications to guide users through - * fulfillment of a business process/goal that takes place over a series of steps, modeled as states. - *

- * Structurally a flow definition is composed of a set of states. A {@link StateDefinition state} is a point in a flow - * where a behavior is executed; for example, showing a view, executing an action, spawning a subflow, or terminating - * the flow. Different types of states execute different behaviors in a polymorphic fashion. Most states are - * {@link TransitionableStateDefinition transitionable states}, meaning they can respond to events by taking the flow - * from one state to another. - *

- * Each flow has exactly one {@link #getStartState() start state} which defines the starting point of the program. - *

- * This interface exposes the flow's identifier, states, and other definitional attributes. It is suitable for - * introspection by tools as well as user-code at flow execution time. - *

- * Flow definitions may be annotated with attributes. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface FlowDefinition extends Annotated { - - /** - * Returns the unique id of this flow. - * @return the flow id - */ - String getId(); - - /** - * Return this flow's starting point. - * @return the start state - */ - StateDefinition getStartState(); - - /** - * Returns the state definition with the specified id. - * @param id the state id - * @return the state definition - * @throws IllegalArgumentException if a state with this id does not exist - */ - StateDefinition getState(String id) throws IllegalArgumentException; - - /** - * Returns the outcomes that are possible for this flow to reach. - * @return the possible outcomes - */ - String[] getPossibleOutcomes(); - - /** - * Returns the class loader used by this flow definition to load classes. - * @return the class loader - */ - ClassLoader getClassLoader(); - - /** - * Returns a reference to application context hosting application objects and services used by this flow definition. - * @return the application context - */ - ApplicationContext getApplicationContext(); - - /** - * Returns true if this flow definition is currently in development (running in development mode). - * @return the development flag - */ - boolean inDevelopment(); - - /** - * Destroy this flow definition, releasing any resources. After the flow is destroyed it cannot be started again. - */ - void destroy(); - +/* + * 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 + * + * https://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.definition; + +import org.springframework.context.ApplicationContext; +import org.springframework.webflow.core.Annotated; + +/** + * The definition of a flow, a program that when executed carries out a task on behalf of a single client. + *

+ * A flow definition is a reusable, self-contained controller module that defines a blue print for an executable user + * task. Flows typically orchestrate controlled navigations or dialogs within web applications to guide users through + * fulfillment of a business process/goal that takes place over a series of steps, modeled as states. + *

+ * Structurally a flow definition is composed of a set of states. A {@link StateDefinition state} is a point in a flow + * where a behavior is executed; for example, showing a view, executing an action, spawning a subflow, or terminating + * the flow. Different types of states execute different behaviors in a polymorphic fashion. Most states are + * {@link TransitionableStateDefinition transitionable states}, meaning they can respond to events by taking the flow + * from one state to another. + *

+ * Each flow has exactly one {@link #getStartState() start state} which defines the starting point of the program. + *

+ * This interface exposes the flow's identifier, states, and other definitional attributes. It is suitable for + * introspection by tools as well as user-code at flow execution time. + *

+ * Flow definitions may be annotated with attributes. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface FlowDefinition extends Annotated { + + /** + * Returns the unique id of this flow. + * @return the flow id + */ + String getId(); + + /** + * Return this flow's starting point. + * @return the start state + */ + StateDefinition getStartState(); + + /** + * Returns the state definition with the specified id. + * @param id the state id + * @return the state definition + * @throws IllegalArgumentException if a state with this id does not exist + */ + StateDefinition getState(String id) throws IllegalArgumentException; + + /** + * Returns the outcomes that are possible for this flow to reach. + * @return the possible outcomes + */ + String[] getPossibleOutcomes(); + + /** + * Returns the class loader used by this flow definition to load classes. + * @return the class loader + */ + ClassLoader getClassLoader(); + + /** + * Returns a reference to application context hosting application objects and services used by this flow definition. + * @return the application context + */ + ApplicationContext getApplicationContext(); + + /** + * Returns true if this flow definition is currently in development (running in development mode). + * @return the development flag + */ + boolean inDevelopment(); + + /** + * Destroy this flow definition, releasing any resources. After the flow is destroyed it cannot be started again. + */ + void destroy(); + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/definition/StateDefinition.java b/spring-webflow/src/main/java/org/springframework/webflow/definition/StateDefinition.java index fe6bada5..6f0a920f 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/definition/StateDefinition.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/definition/StateDefinition.java @@ -1,48 +1,48 @@ -/* - * 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 - * - * https://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.definition; - -import org.springframework.webflow.core.Annotated; - -/** - * A step within a {@link FlowDefinition flow definition} where behavior is executed. - *

- * States have identifiers that are local to their containing flow definitions. They may also be annotated with - * attributes. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface StateDefinition extends Annotated { - - /** - * Returns the flow definition this state belongs to. - * @return the owning flow definition - */ - FlowDefinition getOwner(); - - /** - * Returns this state's identifier, locally unique to is containing flow definition. - * @return the state identifier - */ - String getId(); - - /** - * Returns true if this state is a view state. - * @return true if a view state, false otherwise - */ - boolean isViewState(); +/* + * 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 + * + * https://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.definition; + +import org.springframework.webflow.core.Annotated; + +/** + * A step within a {@link FlowDefinition flow definition} where behavior is executed. + *

+ * States have identifiers that are local to their containing flow definitions. They may also be annotated with + * attributes. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface StateDefinition extends Annotated { + + /** + * Returns the flow definition this state belongs to. + * @return the owning flow definition + */ + FlowDefinition getOwner(); + + /** + * Returns this state's identifier, locally unique to is containing flow definition. + * @return the state identifier + */ + String getId(); + + /** + * Returns true if this state is a view state. + * @return true if a view state, false otherwise + */ + boolean isViewState(); } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/definition/TransitionDefinition.java b/spring-webflow/src/main/java/org/springframework/webflow/definition/TransitionDefinition.java index 1adb920e..2e952ffd 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/definition/TransitionDefinition.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/definition/TransitionDefinition.java @@ -1,41 +1,41 @@ -/* - * 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 - * - * https://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.definition; - -import org.springframework.webflow.core.Annotated; - -/** - * A transition takes a flow from one state to another. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface TransitionDefinition extends Annotated { - - /** - * The identifier of this transition. This id value should be unique among all other transitions in a set. - * @return the transition identifier - */ - String getId(); - - /** - * Returns an identification of the target state of this transition. This could be an actual static state id or - * something more dynamic, like a string representation of an expression evaluating the target state id at flow - * execution time. - * @return the target state identifier - */ - String getTargetStateId(); +/* + * 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 + * + * https://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.definition; + +import org.springframework.webflow.core.Annotated; + +/** + * A transition takes a flow from one state to another. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface TransitionDefinition extends Annotated { + + /** + * The identifier of this transition. This id value should be unique among all other transitions in a set. + * @return the transition identifier + */ + String getId(); + + /** + * Returns an identification of the target state of this transition. This could be an actual static state id or + * something more dynamic, like a string representation of an expression evaluating the target state id at flow + * execution time. + * @return the target state identifier + */ + String getTargetStateId(); } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/definition/TransitionableStateDefinition.java b/spring-webflow/src/main/java/org/springframework/webflow/definition/TransitionableStateDefinition.java index 7d5add28..32369ccd 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/definition/TransitionableStateDefinition.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/definition/TransitionableStateDefinition.java @@ -1,38 +1,38 @@ -/* - * 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 - * - * https://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.definition; - -/** - * A state that can transition to another state. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface TransitionableStateDefinition extends StateDefinition { - - /** - * Returns the available transitions out of this state. - * @return the available state transitions - */ - TransitionDefinition[] getTransitions(); - - /** - * Returns the transition that matches the event with the provided id. - * @param eventId the event id - * @return the transition that matches, or null if no match is found. - */ - TransitionDefinition getTransition(String eventId); +/* + * 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 + * + * https://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.definition; + +/** + * A state that can transition to another state. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface TransitionableStateDefinition extends StateDefinition { + + /** + * Returns the available transitions out of this state. + * @return the available state transitions + */ + TransitionDefinition[] getTransitions(); + + /** + * Returns the transition that matches the event with the provided id. + * @param eventId the event id + * @return the transition that matches, or null if no match is found. + */ + TransitionDefinition getTransition(String eventId); } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionConstructionException.java b/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionConstructionException.java index 44cf5a89..92ce3db2 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionConstructionException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionConstructionException.java @@ -1,50 +1,50 @@ -/* - * 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 - * - * https://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.definition.registry; - -import org.springframework.webflow.core.FlowException; - -/** - * Thrown when a flow definition was found during a lookup operation but could not be constructed. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class FlowDefinitionConstructionException extends FlowException { - - /** - * The id of the flow that could not be constructed. - */ - private String flowDefinitionId; - - /** - * Creates an exception indicating a flow definition could not be constructed. - * @param flowDefinitionId the flow definition identifier - * @param cause the underlying cause of the exception - */ - public FlowDefinitionConstructionException(String flowDefinitionId, Throwable cause) { - super("An exception occurred constructing the flow '" + flowDefinitionId + "'", cause); - this.flowDefinitionId = flowDefinitionId; - } - - /** - * Returns the id of the flow definition that could not be constructed. - * @return the flow id - */ - public String getFlowDefinitionId() { - return flowDefinitionId; - } +/* + * 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 + * + * https://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.definition.registry; + +import org.springframework.webflow.core.FlowException; + +/** + * Thrown when a flow definition was found during a lookup operation but could not be constructed. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class FlowDefinitionConstructionException extends FlowException { + + /** + * The id of the flow that could not be constructed. + */ + private String flowDefinitionId; + + /** + * Creates an exception indicating a flow definition could not be constructed. + * @param flowDefinitionId the flow definition identifier + * @param cause the underlying cause of the exception + */ + public FlowDefinitionConstructionException(String flowDefinitionId, Throwable cause) { + super("An exception occurred constructing the flow '" + flowDefinitionId + "'", cause); + this.flowDefinitionId = flowDefinitionId; + } + + /** + * Returns the id of the flow definition that could not be constructed. + * @return the flow id + */ + public String getFlowDefinitionId() { + return flowDefinitionId; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionHolder.java b/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionHolder.java index 7df6a209..90807abe 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionHolder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionHolder.java @@ -1,66 +1,66 @@ -/* - * 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 - * - * https://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.definition.registry; - -import org.springframework.webflow.definition.FlowDefinition; - -/** - * A holder holding a reference to a Flow definition. Provides a layer of indirection, enabling things like - * "hot-reloadable" flow definitions. - * - * @see FlowDefinitionRegistry#registerFlowDefinition(FlowDefinitionHolder) - * - * @author Keith Donald - */ -public interface FlowDefinitionHolder { - - /** - * Returns the id of the flow definition held by this holder. This is a lightweight method - * callers may call to obtain the id of the flow without triggering full flow definition assembly (which may be an - * expensive operation). - */ - String getFlowDefinitionId(); - - /** - * Returns a descriptive string that identifies the source of this FlowDefinition. This is also a lightweight method - * callers may call to obtain the logical resource where the flow definition resides without triggering flow - * definition assembly. Used for informational purposes. - * @return the flow definition resource string - */ - String getFlowDefinitionResourceString(); - - /** - * Returns the flow definition held by this holder. Calling this method the first time may trigger flow assembly - * (which may be expensive). - * @throws FlowDefinitionConstructionException if there is a problem constructing the target flow definition - */ - FlowDefinition getFlowDefinition() throws FlowDefinitionConstructionException; - - /** - * Refresh the flow definition held by this holder. Calling this method typically triggers flow re-assembly, which - * may include a refresh from an externalized resource such as a file. - * @throws FlowDefinitionConstructionException if there is a problem constructing the target flow definition - */ - void refresh() throws FlowDefinitionConstructionException; - - /** - * Indicates that the system is being shutdown and any resources flow resources should be released. After this - * method is called, calls to {@link #getFlowDefinition()} are undefined. Should only be called once. May be a no-op - * if the held flow was never constructed to begin with. - */ - void destroy(); - +/* + * 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 + * + * https://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.definition.registry; + +import org.springframework.webflow.definition.FlowDefinition; + +/** + * A holder holding a reference to a Flow definition. Provides a layer of indirection, enabling things like + * "hot-reloadable" flow definitions. + * + * @see FlowDefinitionRegistry#registerFlowDefinition(FlowDefinitionHolder) + * + * @author Keith Donald + */ +public interface FlowDefinitionHolder { + + /** + * Returns the id of the flow definition held by this holder. This is a lightweight method + * callers may call to obtain the id of the flow without triggering full flow definition assembly (which may be an + * expensive operation). + */ + String getFlowDefinitionId(); + + /** + * Returns a descriptive string that identifies the source of this FlowDefinition. This is also a lightweight method + * callers may call to obtain the logical resource where the flow definition resides without triggering flow + * definition assembly. Used for informational purposes. + * @return the flow definition resource string + */ + String getFlowDefinitionResourceString(); + + /** + * Returns the flow definition held by this holder. Calling this method the first time may trigger flow assembly + * (which may be expensive). + * @throws FlowDefinitionConstructionException if there is a problem constructing the target flow definition + */ + FlowDefinition getFlowDefinition() throws FlowDefinitionConstructionException; + + /** + * Refresh the flow definition held by this holder. Calling this method typically triggers flow re-assembly, which + * may include a refresh from an externalized resource such as a file. + * @throws FlowDefinitionConstructionException if there is a problem constructing the target flow definition + */ + void refresh() throws FlowDefinitionConstructionException; + + /** + * Indicates that the system is being shutdown and any resources flow resources should be released. After this + * method is called, calls to {@link #getFlowDefinition()} are undefined. Should only be called once. May be a no-op + * if the held flow was never constructed to begin with. + */ + void destroy(); + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionLocator.java b/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionLocator.java index a2c6c600..a4ba2d67 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionLocator.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/FlowDefinitionLocator.java @@ -1,38 +1,38 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.definition.registry; - -import org.springframework.webflow.definition.FlowDefinition; - -/** - * A runtime service locator interface for retrieving flow definitions by id. Flow locators are needed by - * flow executors at runtime to retrieve fully-configured flow definitions to support launching new flow executions. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface FlowDefinitionLocator { - - /** - * Lookup the flow definition with the specified id. - * @param id the flow definition identifier - * @return the flow definition - * @throws NoSuchFlowDefinitionException when the flow definition with the specified id does not exist - * @throws FlowDefinitionConstructionException if there is a problem constructing the identified flow definition - */ - FlowDefinition getFlowDefinition(String id) throws NoSuchFlowDefinitionException, - FlowDefinitionConstructionException; -} +/* + * Copyright 2004-2012 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 + * + * https://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.definition.registry; + +import org.springframework.webflow.definition.FlowDefinition; + +/** + * A runtime service locator interface for retrieving flow definitions by id. Flow locators are needed by + * flow executors at runtime to retrieve fully-configured flow definitions to support launching new flow executions. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface FlowDefinitionLocator { + + /** + * Lookup the flow definition with the specified id. + * @param id the flow definition identifier + * @return the flow definition + * @throws NoSuchFlowDefinitionException when the flow definition with the specified id does not exist + * @throws FlowDefinitionConstructionException if there is a problem constructing the identified flow definition + */ + FlowDefinition getFlowDefinition(String id) throws NoSuchFlowDefinitionException, + FlowDefinitionConstructionException; +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/NoSuchFlowDefinitionException.java b/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/NoSuchFlowDefinitionException.java index 976aa769..45c79049 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/NoSuchFlowDefinitionException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/definition/registry/NoSuchFlowDefinitionException.java @@ -1,48 +1,48 @@ -/* - * 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 - * - * https://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.definition.registry; - -import org.springframework.webflow.core.FlowException; - -/** - * Thrown when no flow definition was found during a lookup operation by a flow locator. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class NoSuchFlowDefinitionException extends FlowException { - - /** - * The id of the flow definition that could not be located. - */ - private String flowDefinitionId; - - /** - * Creates an exception indicating a flow definition could not be found. - * @param flowDefinitionId the flow definition id - */ - public NoSuchFlowDefinitionException(String flowDefinitionId) { - super("No flow definition '" + flowDefinitionId + "' found"); - this.flowDefinitionId = flowDefinitionId; - } - - /** - * Returns the id of the flow definition that could not be found. - */ - public String getFlowDefinitionId() { - return flowDefinitionId; - } +/* + * 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 + * + * https://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.definition.registry; + +import org.springframework.webflow.core.FlowException; + +/** + * Thrown when no flow definition was found during a lookup operation by a flow locator. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class NoSuchFlowDefinitionException extends FlowException { + + /** + * The id of the flow definition that could not be located. + */ + private String flowDefinitionId; + + /** + * Creates an exception indicating a flow definition could not be found. + * @param flowDefinitionId the flow definition id + */ + public NoSuchFlowDefinitionException(String flowDefinitionId) { + super("No flow definition '" + flowDefinitionId + "' found"); + this.flowDefinitionId = flowDefinitionId; + } + + /** + * Returns the id of the flow definition that could not be found. + */ + public String getFlowDefinitionId() { + return flowDefinitionId; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/ActionList.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/ActionList.java index 27f450f9..a9a84c8b 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/ActionList.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/ActionList.java @@ -1,161 +1,161 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.core.style.StylerUtils; -import org.springframework.webflow.execution.Action; -import org.springframework.webflow.execution.ActionExecutor; -import org.springframework.webflow.execution.AnnotatedAction; -import org.springframework.webflow.execution.RequestContext; - -/** - * An ordered, typed list of actions, mainly for use internally by flow artifacts that can execute groups of actions. - * - * @see Flow#getStartActionList() - * @see Flow#getEndActionList() - * @see State#getEntryActionList() - * @see ActionState#getActionList() - * @see TransitionableState#getExitActionList() - * @see ViewState#getRenderActionList() - * - * @author Keith Donald - */ -public class ActionList implements Iterable { - - /** - * The lists of actions. - */ - private List actions = new LinkedList<>(); - - /** - * Add an action to this list. - * @param action the action to add - * @return true if this list's contents changed as a result of the add operation - */ - public boolean add(Action action) { - return actions.add(action); - } - - /** - * Add a collection of actions to this list. - * @param actions the actions to add - * @return true if this list's contents changed as a result of the add operation - */ - public boolean addAll(Action... actions) { - if (actions == null) { - return false; - } - return this.actions.addAll(Arrays.asList(actions)); - } - - /** - * Tests if the action is in this list. - * @param action the action - * @return true if the action is contained in this list, false otherwise - */ - public boolean contains(Action action) { - return actions.contains(action); - } - - /** - * Remove the action instance from this list. - * @param action the action to add - * @return true if this list's contents changed as a result of the remove operation - */ - public boolean remove(Action action) { - return actions.remove(action); - } - - /** - * Returns the size of this action list. - * @return the action list size. - */ - public int size() { - return actions.size(); - } - - /** - * Returns the action in this list at the provided index. - * @param index the action index - * @return the action the action - */ - public Action get(int index) throws IndexOutOfBoundsException { - return actions.get(index); - } - - /** - * Returns the action in this list at the provided index, exposing it as an annotated action. This allows clients to - * access specific properties about a target action instance if they exist. - * @return the action, as an annotated action - */ - public AnnotatedAction getAnnotated(int index) throws IndexOutOfBoundsException { - Action action = get(index); - if (action instanceof AnnotatedAction) { - return (AnnotatedAction) action; - } else { - // wrap the action; no annotations will be available - return new AnnotatedAction(action); - } - } - - /** - * Returns an iterator over this action list. - */ - public Iterator iterator() { - return actions.iterator(); - } - - /** - * Convert this list to a typed action array. - * @return the action list, as a typed array - */ - public Action[] toArray() { - return actions.toArray(new Action[actions.size()]); - } - - /** - * Returns the list of actions in this list as a typed annotated action array. This is a convenience method allowing - * clients to access properties about an action if they exist. - * @return the annotated action list, as a typed array - */ - public AnnotatedAction[] toAnnotatedArray() { - AnnotatedAction[] annotatedActions = new AnnotatedAction[actions.size()]; - for (int i = 0; i < size(); i++) { - annotatedActions[i] = getAnnotated(i); - } - return annotatedActions; - } - - /** - * Executes the actions contained within this action list. Simply iterates over each action and calls execute. - * Action result events are ignored. - * @param context the action execution request context - */ - public void execute(RequestContext context) { - for (Action action : actions) { - ActionExecutor.execute(action, context); - } - } - - public String toString() { - return StylerUtils.style(actions); - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.springframework.core.style.StylerUtils; +import org.springframework.webflow.execution.Action; +import org.springframework.webflow.execution.ActionExecutor; +import org.springframework.webflow.execution.AnnotatedAction; +import org.springframework.webflow.execution.RequestContext; + +/** + * An ordered, typed list of actions, mainly for use internally by flow artifacts that can execute groups of actions. + * + * @see Flow#getStartActionList() + * @see Flow#getEndActionList() + * @see State#getEntryActionList() + * @see ActionState#getActionList() + * @see TransitionableState#getExitActionList() + * @see ViewState#getRenderActionList() + * + * @author Keith Donald + */ +public class ActionList implements Iterable { + + /** + * The lists of actions. + */ + private List actions = new LinkedList<>(); + + /** + * Add an action to this list. + * @param action the action to add + * @return true if this list's contents changed as a result of the add operation + */ + public boolean add(Action action) { + return actions.add(action); + } + + /** + * Add a collection of actions to this list. + * @param actions the actions to add + * @return true if this list's contents changed as a result of the add operation + */ + public boolean addAll(Action... actions) { + if (actions == null) { + return false; + } + return this.actions.addAll(Arrays.asList(actions)); + } + + /** + * Tests if the action is in this list. + * @param action the action + * @return true if the action is contained in this list, false otherwise + */ + public boolean contains(Action action) { + return actions.contains(action); + } + + /** + * Remove the action instance from this list. + * @param action the action to add + * @return true if this list's contents changed as a result of the remove operation + */ + public boolean remove(Action action) { + return actions.remove(action); + } + + /** + * Returns the size of this action list. + * @return the action list size. + */ + public int size() { + return actions.size(); + } + + /** + * Returns the action in this list at the provided index. + * @param index the action index + * @return the action the action + */ + public Action get(int index) throws IndexOutOfBoundsException { + return actions.get(index); + } + + /** + * Returns the action in this list at the provided index, exposing it as an annotated action. This allows clients to + * access specific properties about a target action instance if they exist. + * @return the action, as an annotated action + */ + public AnnotatedAction getAnnotated(int index) throws IndexOutOfBoundsException { + Action action = get(index); + if (action instanceof AnnotatedAction) { + return (AnnotatedAction) action; + } else { + // wrap the action; no annotations will be available + return new AnnotatedAction(action); + } + } + + /** + * Returns an iterator over this action list. + */ + public Iterator iterator() { + return actions.iterator(); + } + + /** + * Convert this list to a typed action array. + * @return the action list, as a typed array + */ + public Action[] toArray() { + return actions.toArray(new Action[actions.size()]); + } + + /** + * Returns the list of actions in this list as a typed annotated action array. This is a convenience method allowing + * clients to access properties about an action if they exist. + * @return the annotated action list, as a typed array + */ + public AnnotatedAction[] toAnnotatedArray() { + AnnotatedAction[] annotatedActions = new AnnotatedAction[actions.size()]; + for (int i = 0; i < size(); i++) { + annotatedActions[i] = getAnnotated(i); + } + return annotatedActions; + } + + /** + * Executes the actions contained within this action list. Simply iterates over each action and calls execute. + * Action result events are ignored. + * @param context the action execution request context + */ + public void execute(RequestContext context) { + for (Action action : actions) { + ActionExecutor.execute(action, context); + } + } + + public String toString() { + return StylerUtils.style(actions); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/ActionState.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/ActionState.java index 254f0272..b55a58a9 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/ActionState.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/ActionState.java @@ -1,168 +1,168 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import java.util.Iterator; - -import org.springframework.core.style.StylerUtils; -import org.springframework.core.style.ToStringCreator; -import org.springframework.webflow.execution.Action; -import org.springframework.webflow.execution.ActionExecutor; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.execution.RequestContext; - -/** - * A transitionable state that executes one or more actions when entered. When the action(s) are executed this state - * responds to their result(s) to decide what state to transition to next. - *

- * If more than one action is configured they are executed in an ordered chain until one returns a result event that - * matches a state transition out of this state. This is a form of the Chain of Responsibility (CoR) pattern. - *

- * The result of an action's execution is typically the criteria for a transition out of this state. Additional - * information in the current {@link RequestContext} may also be tested as part of custom transitional criteria, - * allowing for sophisticated transition expressions that reason on contextual state. - * - * @see org.springframework.webflow.execution.Action - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class ActionState extends TransitionableState { - - /** - * The list of actions to be executed when this state is entered. - */ - private ActionList actionList = new ActionList(); - - /** - * Creates a new action state. - * @param flow the owning flow - * @param id the state identifier (must be unique to the flow) - * @throws IllegalArgumentException when this state cannot be added to given flow, e.g. beasue the id is not unique - * @see #getActionList() - */ - public ActionState(Flow flow, String id) throws IllegalArgumentException { - super(flow, id); - } - - /** - * Returns the list of actions executable by this action state. The returned list is mutable. - * @return the state action list - */ - public ActionList getActionList() { - return actionList; - } - - /* - * Overrides getRequiredTransition(RequestContext) to throw a local NoMatchingActionResultTransitionException if a - * transition on the occurrence of an action result event cannot be matched. Used to facilitate an action invocation - * chain.

Note that we cannot catch NoMatchingTransitionException since that could lead to unwanted situations - * where we're catching an exception that's generated by another state, e.g. because of a configuration error! - */ - public Transition getRequiredTransition(RequestContext context) throws NoMatchingTransitionException { - Transition transition = getTransitionSet().getTransition(context); - if (transition == null) { - throw new NoMatchingActionResultTransitionException(this, context.getCurrentEvent()); - } - return transition; - } - - /** - * Specialization of State's doEnter template method that executes behavior specific to this state type - * in polymorphic fashion. - *

- * This implementation iterates over each configured Action instance and executes it. Execution - * continues until an Action returns a result event that matches a transition in this request context, - * or the set of all actions is exhausted. - * @param context the control context for the currently executing flow, used by this state to manipulate the flow - * execution - * @throws FlowExecutionException if an exception occurs in this state - */ - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - int executionCount = 0; - String[] eventIds = new String[actionList.size()]; - Iterator it = actionList.iterator(); - while (it.hasNext()) { - Action action = it.next(); - Event event = ActionExecutor.execute(action, context); - if (event != null) { - eventIds[executionCount] = event.getId(); - try { - context.handleEvent(event); - return; - } catch (NoMatchingActionResultTransitionException e) { - if (logger.isDebugEnabled()) { - logger.debug("Action execution [" - + (executionCount + 1) - + "] resulted in no matching transition on event '" - + event.getId() - + "'" - + (it.hasNext() ? ": proceeding to the next action in the list" - : ": action list exhausted")); - } - } - } else { - if (logger.isDebugEnabled()) { - logger.debug("Action execution [" - + (executionCount + 1) - + "] returned a [null] event" - + (it.hasNext() ? ": proceeding to the next action in the list" : ": action list exhausted")); - } - eventIds[executionCount] = null; - } - executionCount++; - } - if (executionCount > 0) { - throw new NoMatchingTransitionException(getFlow().getId(), getId(), context.getCurrentEvent(), - "No transition was matched on the event(s) signaled by the [" + executionCount - + "] action(s) that executed in this action state '" + getId() + "' of flow '" - + getFlow().getId() + "'; transitions must be defined to handle action result outcomes -- " - + "possible flow configuration error? Note: the eventIds signaled were: '" - + StylerUtils.style(eventIds) - + "', while the supported set of transitional criteria for this action state is '" - + StylerUtils.style(getTransitionSet().getTransitionCriterias()) + "'"); - } else { - throw new IllegalStateException( - "No actions were executed, thus I cannot execute any state transition " - + "-- programmer configuration error; make sure you add at least one action to this state's action list"); - } - } - - protected void appendToString(ToStringCreator creator) { - creator.append("actionList", actionList); - super.appendToString(creator); - } - - /** - * Local "no transition found" exception used to report that an action result could not be mapped to a state - * transition. - * @author Keith Donald - * @author Erwin Vervaet - */ - private static class NoMatchingActionResultTransitionException extends NoMatchingTransitionException { - - /** - * Creates a new exception. - * @param state the action state - * @param resultEvent the action result event - */ - public NoMatchingActionResultTransitionException(ActionState state, Event resultEvent) { - super(state.getFlow().getId(), state.getId(), resultEvent, - "Cannot find a transition matching an action result event; continuing with next action..."); - } - } +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import java.util.Iterator; + +import org.springframework.core.style.StylerUtils; +import org.springframework.core.style.ToStringCreator; +import org.springframework.webflow.execution.Action; +import org.springframework.webflow.execution.ActionExecutor; +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.execution.RequestContext; + +/** + * A transitionable state that executes one or more actions when entered. When the action(s) are executed this state + * responds to their result(s) to decide what state to transition to next. + *

+ * If more than one action is configured they are executed in an ordered chain until one returns a result event that + * matches a state transition out of this state. This is a form of the Chain of Responsibility (CoR) pattern. + *

+ * The result of an action's execution is typically the criteria for a transition out of this state. Additional + * information in the current {@link RequestContext} may also be tested as part of custom transitional criteria, + * allowing for sophisticated transition expressions that reason on contextual state. + * + * @see org.springframework.webflow.execution.Action + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class ActionState extends TransitionableState { + + /** + * The list of actions to be executed when this state is entered. + */ + private ActionList actionList = new ActionList(); + + /** + * Creates a new action state. + * @param flow the owning flow + * @param id the state identifier (must be unique to the flow) + * @throws IllegalArgumentException when this state cannot be added to given flow, e.g. beasue the id is not unique + * @see #getActionList() + */ + public ActionState(Flow flow, String id) throws IllegalArgumentException { + super(flow, id); + } + + /** + * Returns the list of actions executable by this action state. The returned list is mutable. + * @return the state action list + */ + public ActionList getActionList() { + return actionList; + } + + /* + * Overrides getRequiredTransition(RequestContext) to throw a local NoMatchingActionResultTransitionException if a + * transition on the occurrence of an action result event cannot be matched. Used to facilitate an action invocation + * chain.

Note that we cannot catch NoMatchingTransitionException since that could lead to unwanted situations + * where we're catching an exception that's generated by another state, e.g. because of a configuration error! + */ + public Transition getRequiredTransition(RequestContext context) throws NoMatchingTransitionException { + Transition transition = getTransitionSet().getTransition(context); + if (transition == null) { + throw new NoMatchingActionResultTransitionException(this, context.getCurrentEvent()); + } + return transition; + } + + /** + * Specialization of State's doEnter template method that executes behavior specific to this state type + * in polymorphic fashion. + *

+ * This implementation iterates over each configured Action instance and executes it. Execution + * continues until an Action returns a result event that matches a transition in this request context, + * or the set of all actions is exhausted. + * @param context the control context for the currently executing flow, used by this state to manipulate the flow + * execution + * @throws FlowExecutionException if an exception occurs in this state + */ + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + int executionCount = 0; + String[] eventIds = new String[actionList.size()]; + Iterator it = actionList.iterator(); + while (it.hasNext()) { + Action action = it.next(); + Event event = ActionExecutor.execute(action, context); + if (event != null) { + eventIds[executionCount] = event.getId(); + try { + context.handleEvent(event); + return; + } catch (NoMatchingActionResultTransitionException e) { + if (logger.isDebugEnabled()) { + logger.debug("Action execution [" + + (executionCount + 1) + + "] resulted in no matching transition on event '" + + event.getId() + + "'" + + (it.hasNext() ? ": proceeding to the next action in the list" + : ": action list exhausted")); + } + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("Action execution [" + + (executionCount + 1) + + "] returned a [null] event" + + (it.hasNext() ? ": proceeding to the next action in the list" : ": action list exhausted")); + } + eventIds[executionCount] = null; + } + executionCount++; + } + if (executionCount > 0) { + throw new NoMatchingTransitionException(getFlow().getId(), getId(), context.getCurrentEvent(), + "No transition was matched on the event(s) signaled by the [" + executionCount + + "] action(s) that executed in this action state '" + getId() + "' of flow '" + + getFlow().getId() + "'; transitions must be defined to handle action result outcomes -- " + + "possible flow configuration error? Note: the eventIds signaled were: '" + + StylerUtils.style(eventIds) + + "', while the supported set of transitional criteria for this action state is '" + + StylerUtils.style(getTransitionSet().getTransitionCriterias()) + "'"); + } else { + throw new IllegalStateException( + "No actions were executed, thus I cannot execute any state transition " + + "-- programmer configuration error; make sure you add at least one action to this state's action list"); + } + } + + protected void appendToString(ToStringCreator creator) { + creator.append("actionList", actionList); + super.appendToString(creator); + } + + /** + * Local "no transition found" exception used to report that an action result could not be mapped to a state + * transition. + * @author Keith Donald + * @author Erwin Vervaet + */ + private static class NoMatchingActionResultTransitionException extends NoMatchingTransitionException { + + /** + * Creates a new exception. + * @param state the action state + * @param resultEvent the action result event + */ + public NoMatchingActionResultTransitionException(ActionState state, Event resultEvent) { + super(state.getFlow().getId(), state.getId(), resultEvent, + "Cannot find a transition matching an action result event; continuing with next action..."); + } + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/DecisionState.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/DecisionState.java index 40d79a44..d8a30164 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/DecisionState.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/DecisionState.java @@ -1,53 +1,53 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.execution.RequestContext; - -/** - * A simple transitionable state that when entered will execute the first transition whose matching criteria evaluates - * to true in the {@link RequestContext context} of the current request. - *

- * A decision state is a convenient, simple way to encapsulate reusable state transition logic in one place. - * - * @author Keith Donald - */ -public class DecisionState extends TransitionableState { - - /** - * Creates a new decision state. - * @param flow the owning flow - * @param stateId the state identifier (must be unique to the flow) - * @throws IllegalArgumentException when this state cannot be added to given flow, e.g. because the id is not unique - */ - public DecisionState(Flow flow, String stateId) throws IllegalArgumentException { - super(flow, stateId); - } - - /** - * Specialization of State's doEnter template method that executes behavior specific to this state type - * in polymorphic fashion. - *

- * Simply looks up the first transition that matches the state of the context and executes it. - * @param context the control context for the currently executing flow, used by this state to manipulate the flow - * execution - * @throws FlowExecutionException if an exception occurs in this state - */ - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - getRequiredTransition(context).execute(this, context); - } +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.execution.RequestContext; + +/** + * A simple transitionable state that when entered will execute the first transition whose matching criteria evaluates + * to true in the {@link RequestContext context} of the current request. + *

+ * A decision state is a convenient, simple way to encapsulate reusable state transition logic in one place. + * + * @author Keith Donald + */ +public class DecisionState extends TransitionableState { + + /** + * Creates a new decision state. + * @param flow the owning flow + * @param stateId the state identifier (must be unique to the flow) + * @throws IllegalArgumentException when this state cannot be added to given flow, e.g. because the id is not unique + */ + public DecisionState(Flow flow, String stateId) throws IllegalArgumentException { + super(flow, stateId); + } + + /** + * Specialization of State's doEnter template method that executes behavior specific to this state type + * in polymorphic fashion. + *

+ * Simply looks up the first transition that matches the state of the context and executes it. + * @param context the control context for the currently executing flow, used by this state to manipulate the flow + * execution + * @throws FlowExecutionException if an exception occurs in this state + */ + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + getRequiredTransition(context).execute(this, context); + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/EndState.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/EndState.java index 5b1eba1e..2f3a679f 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/EndState.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/EndState.java @@ -1,130 +1,130 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import org.springframework.binding.mapping.Mapper; -import org.springframework.binding.mapping.MappingResults; -import org.springframework.core.style.ToStringCreator; -import org.springframework.webflow.core.collection.LocalAttributeMap; -import org.springframework.webflow.execution.Action; -import org.springframework.webflow.execution.ActionExecutor; -import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.execution.FlowSession; -import org.springframework.webflow.execution.RequestContext; - -/** - * A state that ends a flow when entered. This state ends the active flow session of an ongoing flow execution. - *

- * If the ended session is the "root flow session" the entire flow execution ends, signaling the end of a logical - * conversation. - *

- * If the terminated session was acting as a subflow, the flow execution continues and control is returned to the parent - * flow session. In that case, this state returns an ending result event the resuming parent flow responds to. - *

- * An end state may be configured with a renderer to render a final response. This renderer will be invoked if the end - * state terminates the entire flow execution. - * - * @see org.springframework.webflow.engine.SubflowState - * - * @author Keith Donald - * @author Colin Sampaleanu - * @author Erwin Vervaet - */ -public class EndState extends State { - - /** - * The renderer that will render the final response when a flow execution terminates. - */ - private Action finalResponseAction; - - /** - * The attribute mapper for mapping output attributes exposed by this end state when it is entered. - */ - private Mapper outputMapper; - - /** - * Create a new end state with no associated view. - * @param flow the owning flow - * @param id the state identifier (must be unique to the flow) - * @throws IllegalArgumentException when this state cannot be added to given flow, e.g. because the id is not unique - * @see State#State(Flow, String) - * @see #setFinalResponseAction(Action) - * @see #setOutputMapper(Mapper) - */ - public EndState(Flow flow, String id) throws IllegalArgumentException { - super(flow, id); - } - - /** - * Sets the renderer that will render the final flow execution response. - */ - public void setFinalResponseAction(Action finalResponseAction) { - this.finalResponseAction = finalResponseAction; - } - - /** - * Sets the attribute mapper to use for mapping output attributes exposed by this end state when it is entered. - */ - public void setOutputMapper(Mapper outputMapper) { - this.outputMapper = outputMapper; - } - - /** - * Specialization of State's doEnter template method that executes behavior specific to this state type - * in polymorphic fashion. - *

- * This implementation pops the top (active) flow session off the execution stack, ending it, and resumes control in - * the parent flow (if necessary). If the ended session is the root flow, a final response is rendered. - * @param context the control context for the currently executing flow, used by this state to manipulate the flow - * execution - * @throws FlowExecutionException if an exception occurs in this state - */ - protected void doEnter(final RequestControlContext context) throws FlowExecutionException { - FlowSession activeSession = context.getFlowExecutionContext().getActiveSession(); - if (activeSession.isRoot()) { - // entire flow execution is ending; issue the final response - if (finalResponseAction != null && !context.getExternalContext().isResponseComplete()) { - ActionExecutor.execute(finalResponseAction, context); - context.getExternalContext().recordResponseComplete(); - } - context.endActiveFlowSession(getId(), createSessionOutput(context)); - } else { - // there is a parent flow that will resume (this flow is a subflow) - LocalAttributeMap sessionOutput = createSessionOutput(context); - context.endActiveFlowSession(getId(), sessionOutput); - } - } - - /** - * Returns the subflow output map. This will invoke the output mapper (if any) to map data available in the flow - * execution request context into a newly created empty map. - */ - protected LocalAttributeMap createSessionOutput(RequestContext context) { - LocalAttributeMap output = new LocalAttributeMap<>(); - if (outputMapper != null) { - MappingResults results = outputMapper.map(context, output); - if (results != null && results.hasErrorResults()) { - throw new FlowOutputMappingException(getOwner().getId(), getId(), results); - } - } - return output; - } - - protected void appendToString(ToStringCreator creator) { - creator.append("finalResponseAction", finalResponseAction).append("outputMapper", outputMapper); - } - -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import org.springframework.binding.mapping.Mapper; +import org.springframework.binding.mapping.MappingResults; +import org.springframework.core.style.ToStringCreator; +import org.springframework.webflow.core.collection.LocalAttributeMap; +import org.springframework.webflow.execution.Action; +import org.springframework.webflow.execution.ActionExecutor; +import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.execution.FlowSession; +import org.springframework.webflow.execution.RequestContext; + +/** + * A state that ends a flow when entered. This state ends the active flow session of an ongoing flow execution. + *

+ * If the ended session is the "root flow session" the entire flow execution ends, signaling the end of a logical + * conversation. + *

+ * If the terminated session was acting as a subflow, the flow execution continues and control is returned to the parent + * flow session. In that case, this state returns an ending result event the resuming parent flow responds to. + *

+ * An end state may be configured with a renderer to render a final response. This renderer will be invoked if the end + * state terminates the entire flow execution. + * + * @see org.springframework.webflow.engine.SubflowState + * + * @author Keith Donald + * @author Colin Sampaleanu + * @author Erwin Vervaet + */ +public class EndState extends State { + + /** + * The renderer that will render the final response when a flow execution terminates. + */ + private Action finalResponseAction; + + /** + * The attribute mapper for mapping output attributes exposed by this end state when it is entered. + */ + private Mapper outputMapper; + + /** + * Create a new end state with no associated view. + * @param flow the owning flow + * @param id the state identifier (must be unique to the flow) + * @throws IllegalArgumentException when this state cannot be added to given flow, e.g. because the id is not unique + * @see State#State(Flow, String) + * @see #setFinalResponseAction(Action) + * @see #setOutputMapper(Mapper) + */ + public EndState(Flow flow, String id) throws IllegalArgumentException { + super(flow, id); + } + + /** + * Sets the renderer that will render the final flow execution response. + */ + public void setFinalResponseAction(Action finalResponseAction) { + this.finalResponseAction = finalResponseAction; + } + + /** + * Sets the attribute mapper to use for mapping output attributes exposed by this end state when it is entered. + */ + public void setOutputMapper(Mapper outputMapper) { + this.outputMapper = outputMapper; + } + + /** + * Specialization of State's doEnter template method that executes behavior specific to this state type + * in polymorphic fashion. + *

+ * This implementation pops the top (active) flow session off the execution stack, ending it, and resumes control in + * the parent flow (if necessary). If the ended session is the root flow, a final response is rendered. + * @param context the control context for the currently executing flow, used by this state to manipulate the flow + * execution + * @throws FlowExecutionException if an exception occurs in this state + */ + protected void doEnter(final RequestControlContext context) throws FlowExecutionException { + FlowSession activeSession = context.getFlowExecutionContext().getActiveSession(); + if (activeSession.isRoot()) { + // entire flow execution is ending; issue the final response + if (finalResponseAction != null && !context.getExternalContext().isResponseComplete()) { + ActionExecutor.execute(finalResponseAction, context); + context.getExternalContext().recordResponseComplete(); + } + context.endActiveFlowSession(getId(), createSessionOutput(context)); + } else { + // there is a parent flow that will resume (this flow is a subflow) + LocalAttributeMap sessionOutput = createSessionOutput(context); + context.endActiveFlowSession(getId(), sessionOutput); + } + } + + /** + * Returns the subflow output map. This will invoke the output mapper (if any) to map data available in the flow + * execution request context into a newly created empty map. + */ + protected LocalAttributeMap createSessionOutput(RequestContext context) { + LocalAttributeMap output = new LocalAttributeMap<>(); + if (outputMapper != null) { + MappingResults results = outputMapper.map(context, output); + if (results != null && results.hasErrorResults()) { + throw new FlowOutputMappingException(getOwner().getId(), getId(), results); + } + } + return output; + } + + protected void appendToString(ToStringCreator creator) { + creator.append("finalResponseAction", finalResponseAction).append("outputMapper", outputMapper); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java index 4064c10b..3e85bc15 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/Flow.java @@ -1,656 +1,656 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.binding.mapping.Mapper; -import org.springframework.binding.mapping.MappingResults; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.style.StylerUtils; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.StringUtils; -import org.springframework.webflow.core.AnnotatedObject; -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.StateDefinition; -import org.springframework.webflow.definition.TransitionDefinition; -import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.execution.RequestContext; - -/** - * A single flow definition. A Flow definition is a reusable, self-contained controller module that provides the blue - * print for a user dialog or conversation. Flows typically drive controlled navigations within web applications to - * guide users through fulfillment of a business process/goal that takes place over a series of steps, modeled as - * states. - *

- * A simple Flow definition could do nothing more than execute an action and display a view all in one request. A more - * elaborate Flow definition may be long-lived and execute across a series of requests, invoking many possible paths, - * actions, and subflows. - *

- * Especially in Intranet applications there are often "controlled navigations" where the user is not free to do what he - * or she wants but must follow the guidelines provided by the system to complete a process that is transactional in - * nature (the quintessential example would be a 'checkout' flow of a shopping cart application). This is a typical use - * case appropriate to model as a flow. - *

- * Structurally a Flow is composed of a set of states. A {@link State} is a point in a flow where a behavior is - * executed; for example, showing a view, executing an action, spawning a subflow, or terminating the flow. Different - * types of states execute different behaviors in a polymorphic fashion. - *

- * Each {@link TransitionableState} type has one or more transitions that when executed move a flow to another state. - * These transitions define the supported paths through the flow. - *

- * A state transition is triggered by the occurrence of an event. An event is something that happens the flow should - * respond to, for example a user input event like ("submit") or an action execution result event like ("success"). When - * an event occurs in a state of a Flow that event drives a state transition that decides what to do next. - *

- * Each Flow has exactly one start state. A start state is simply a marker noting the state executions of this Flow - * definition should start in. The first state added to the flow will become the start state by default. - *

- * Flow definitions may have one or more flow exception handlers. A {@link FlowExecutionExceptionHandler} can execute - * custom behavior in response to a specific exception (or set of exceptions) that occur in a state of one of this - * flow's executions. - *

- * Instances of this class are typically built by {@link org.springframework.webflow.engine.builder.FlowBuilder} - * implementations but may also be directly instantiated. - *

- * This class and the rest of the Spring Web Flow (SWF) engine have been designed with minimal dependencies on other - * libraries. Spring Web Flow is usable in a standalone fashion. The engine system is fully usable outside an HTTP - * servlet environment, for example in tests, or standalone applications. One of the major architectural - * benefits of Spring Web Flow is the ability to design reusable, high-level controller modules that may be executed in - * any environment. - *

- * Note: flows are singleton definition objects so they should be thread-safe. You can think a flow definition as - * analogous to a Java class, defining all the behavior of an application module. The core behaviors - * {@link #start(RequestControlContext, MutableAttributeMap) start}, {@link #resume(RequestControlContext)}, - * {@link #handleEvent(RequestControlContext) on event}, - * {@link #end(RequestControlContext, String, MutableAttributeMap) end}, and - * {@link #handleException(FlowExecutionException, RequestControlContext)}. Each method accepts a {@link RequestContext - * request context} that allows for this flow to access execution state in a thread safe manner. A flow execution is - * what models a running instance of this flow definition, somewhat analogous to a java object that is an instance of a - * class. - * - * @see org.springframework.webflow.engine.State - * @see org.springframework.webflow.engine.ActionState - * @see org.springframework.webflow.engine.ViewState - * @see org.springframework.webflow.engine.SubflowState - * @see org.springframework.webflow.engine.EndState - * @see org.springframework.webflow.engine.DecisionState - * @see org.springframework.webflow.engine.Transition - * @see org.springframework.webflow.engine.FlowExecutionExceptionHandler - * - * @author Keith Donald - * @author Erwin Vervaet - * @author Colin Sampaleanu - * @author Jeremy Grelle - */ -public class Flow extends AnnotatedObject implements FlowDefinition { - - /** - * Logger, can be used in subclasses. - */ - protected final Log logger = LogFactory.getLog(getClass()); - - /** - * An assigned flow identifier uniquely identifying this flow among all other flows. - */ - private String id; - - /** - * The set of state definitions for this flow. - */ - private Set states = new LinkedHashSet<>(9); - - /** - * The default start state for this flow. - */ - private State startState; - - /** - * The set of flow variables created by this flow. - */ - private Map variables = new LinkedHashMap<>(); - - /** - * The mapper to map flow input attributes. - */ - private Mapper inputMapper; - - /** - * The list of actions to execute when this flow starts. - *

- * Start actions should execute with care as during startup a flow session has not yet fully initialized and some - * properties like its "currentState" have not yet been set. - */ - private ActionList startActionList = new ActionList(); - - /** - * The set of global transitions that are shared by all states of this flow. - */ - private TransitionSet globalTransitionSet = new TransitionSet(); - - /** - * The list of actions to execute when this flow ends. - */ - private ActionList endActionList = new ActionList(); - - /** - * The mapper to map flow output attributes. - */ - private Mapper outputMapper; - - /** - * The set of exception handlers for this flow. - */ - private FlowExecutionExceptionHandlerSet exceptionHandlerSet = new FlowExecutionExceptionHandlerSet(); - - /** - * An optional application context hosting services needed by this flow. - */ - private ApplicationContext applicationContext; - - /** - * Construct a new flow definition with the given id. The id should be unique among all flows. - * @param id the flow identifier - */ - public Flow(String id) { - Assert.hasText(id, "This flow must be uniquely identified"); - this.id = id; - } - - // convenient static factory methods - - /** - * Create a new flow with the given id and attributes. - * @param id the flow id - * @param attributes the attributes - * @return the flow - */ - public static Flow create(String id, AttributeMap attributes) { - Flow flow = new Flow(id); - flow.getAttributes().putAll(attributes); - return flow; - } - - // implementing FlowDefinition - - public String getId() { - return id; - } - - public StateDefinition getStartState() { - if (startState == null) { - throw new IllegalStateException("No start state has been set for this flow ('" + getId() - + "') -- flow builder configuration error?"); - } - return startState; - } - - public StateDefinition getState(String stateId) { - return getStateInstance(stateId); - } - - public String[] getPossibleOutcomes() { - List possibleOutcomes = new ArrayList<>(); - for (State state : states) { - if (state instanceof EndState) { - possibleOutcomes.add(state.getId()); - } - } - return possibleOutcomes.toArray(new String[possibleOutcomes.size()]); - } - - public ClassLoader getClassLoader() { - if (applicationContext != null) { - return applicationContext.getClassLoader(); - } else { - return ClassUtils.getDefaultClassLoader(); - } - } - - public ApplicationContext getApplicationContext() { - return applicationContext; - } - - public boolean inDevelopment() { - return getAttributes().getBoolean("development", false); - } - - /** - * Add given state definition to this flow definition. Marked protected, as this method is to be called by the - * (privileged) state definition classes themselves during state construction as part of a FlowBuilder invocation. - * @param state the state to add - * @throws IllegalArgumentException when the state cannot be added to the flow; for instance if another state shares - * the same id as the one provided or if given state already belongs to another flow - */ - protected void add(State state) throws IllegalArgumentException { - if (this != state.getFlow() && state.getFlow() != null) { - throw new IllegalArgumentException("State " + state + " cannot be added to this flow '" + getId() - + "' -- it already belongs to a different flow: '" + state.getFlow().getId() + "'"); - } - if (this.states.contains(state) || this.containsState(state.getId())) { - throw new IllegalArgumentException("This flow '" + getId() + "' already contains a state with id '" - + state.getId() + "' -- state ids must be locally unique to the flow definition; " - + "existing state-ids of this flow include: " + StylerUtils.style(getStateIds())); - } - boolean firstAdd = states.isEmpty(); - states.add(state); - if (firstAdd) { - setStartState(state); - } - } - - /** - * Returns the number of states defined in this flow. - * @return the state count - */ - public int getStateCount() { - return states.size(); - } - - /** - * Is a state with the provided id present in this flow? - * @param stateId the state id - * @return true if yes, false otherwise - */ - public boolean containsState(String stateId) { - for (State state : states) { - if (state.getId().equals(stateId)) { - return true; - } - } - return false; - } - - /** - * Set the start state for this flow to the state with the provided stateId; a state must exist by the - * provided stateId. - * @param stateId the id of the new start state - * @throws IllegalArgumentException when no state exists with the id you provided - */ - public void setStartState(String stateId) throws IllegalArgumentException { - setStartState(getStateInstance(stateId)); - } - - /** - * Set the start state for this flow to the state provided; any state may be the start state. - * @param state the new start state - * @throws IllegalArgumentException given state has not been added to this flow - */ - public void setStartState(State state) throws IllegalArgumentException { - if (!states.contains(state)) { - throw new IllegalArgumentException("State '" + state + "' is not a state of flow '" + getId() + "'"); - } - startState = state; - } - - /** - * Return the TransitionableState with given stateId. - * @param stateId id of the state to look up - * @return the transitionable state - * @throws IllegalArgumentException if the identified state cannot be found - * @throws ClassCastException when the identified state is not transitionable - */ - public TransitionableState getTransitionableState(String stateId) throws IllegalArgumentException, - ClassCastException { - State state = getStateInstance(stateId); - if (state != null && !(state instanceof TransitionableState)) { - throw new ClassCastException("The state '" + stateId + "' of flow '" + getId() + "' must be transitionable"); - } - return (TransitionableState) state; - } - - /** - * Lookup the identified state instance of this flow. - * @param stateId the state id - * @return the state - * @throws IllegalArgumentException if the identified state cannot be found - */ - public State getStateInstance(String stateId) throws IllegalArgumentException { - if (!StringUtils.hasText(stateId)) { - throw new IllegalArgumentException("The specified stateId is invalid: state identifiers must be non-blank"); - } - for (State state : states) { - if (state.getId().equals(stateId)) { - return state; - } - } - throw new IllegalArgumentException("Cannot find state with id '" + stateId + "' in flow '" + getId() + "' -- " - + "Known state ids are '" + StylerUtils.style(getStateIds()) + "'"); - } - - /** - * Convenience accessor that returns an ordered array of the String ids for the state definitions - * associated with this flow definition. - * @return the state ids - */ - public String[] getStateIds() { - String[] stateIds = new String[getStateCount()]; - int i = 0; - for (State state : states) { - stateIds[i++] = state.getId(); - } - return stateIds; - } - - /** - * Adds a flow variable. - * @param variable the variable - */ - public void addVariable(FlowVariable variable) { - variables.put(variable.getName(), variable); - } - - /** - * Adds flow variables. - * @param variables the variables - */ - public void addVariables(FlowVariable... variables) { - if (variables == null) { - return; - } - for (FlowVariable variable : variables) { - addVariable(variable); - } - } - - /** - * Returns the flow variable with the given name. - * @param name the name of the variable - */ - public FlowVariable getVariable(String name) { - return variables.get(name); - } - - /** - * Returns the flow variables. - */ - public FlowVariable[] getVariables() { - return variables.values().toArray(new FlowVariable[variables.size()]); - } - - /** - * Returns the configured flow input mapper, or null if none. - * @return the input mapper - */ - public Mapper getInputMapper() { - return inputMapper; - } - - /** - * Sets the mapper to map flow input attributes. - * @param inputMapper the input mapper - */ - public void setInputMapper(Mapper inputMapper) { - this.inputMapper = inputMapper; - } - - /** - * Returns the list of actions executed by this flow when an execution of the flow starts. The returned list - * is mutable. - * @return the start action list - */ - public ActionList getStartActionList() { - return startActionList; - } - - /** - * Returns the list of actions executed by this flow when an execution of the flow ends. The returned list is - * mutable. - * @return the end action list - */ - public ActionList getEndActionList() { - return endActionList; - } - - /** - * Returns the configured flow output mapper, or null if none. - * @return the output mapper - */ - public Mapper getOutputMapper() { - return outputMapper; - } - - /** - * Sets the mapper to map flow output attributes. - * @param outputMapper the output mapper - */ - public void setOutputMapper(Mapper outputMapper) { - this.outputMapper = outputMapper; - } - - /** - * Returns the set of exception handlers, allowing manipulation of how exceptions are handled when thrown during - * flow execution. Exception handlers are invoked when an exception occurs at execution time and can execute custom - * exception handling logic as well as select an error view to display. Exception handlers attached at the flow - * level have an opportunity to handle exceptions that aren't handled at the state level. - * @return the exception handler set - */ - public FlowExecutionExceptionHandlerSet getExceptionHandlerSet() { - return exceptionHandlerSet; - } - - /** - * Returns the set of transitions eligible for execution by this flow if no state-level transition is matched. The - * returned set is mutable. - * @return the global transition set - */ - public TransitionSet getGlobalTransitionSet() { - return globalTransitionSet; - } - - /** - * Returns the transition that matches the event with the provided id. - * @param eventId the event id - * @return the transition that matches, or null if no match is found. - */ - public TransitionDefinition getGlobalTransition(String eventId) { - for (Transition transition : globalTransitionSet) { - if (transition.getId().equals(eventId)) { - return transition; - } - } - return null; - } - - /** - * Sets a reference to the application context hosting application objects needed by this flow. - * @param applicationContext the application context - */ - public void setApplicationContext(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - // id based equality - - public boolean equals(Object o) { - if (!(o instanceof Flow)) { - return false; - } - Flow other = (Flow) o; - return id.equals(other.id); - } - - public int hashCode() { - return id.hashCode(); - } - - // behavioral code, could be overridden in subclasses - - /** - * Start a new session for this flow in its start state. This boils down to the following: - *

    - *
  1. Create (setup) all registered flow variables ({@link #addVariable(FlowVariable)}) in flow scope.
  2. - *
  3. Map provided input data into the flow. Typically data will be mapped into flow scope using the registered - * input mapper ({@link #setInputMapper(Mapper)}).
  4. - *
  5. Execute all registered start actions ( {@link #getStartActionList()}).
  6. - *
  7. Enter the configured start state ({@link #setStartState(State)})
  8. - *
- * @param context the flow execution control context - * @param input eligible input into the session - * @throws FlowExecutionException when an exception occurs starting the flow - */ - public void start(RequestControlContext context, MutableAttributeMap input) throws FlowExecutionException { - assertStartStateSet(); - createVariables(context); - if (inputMapper != null) { - MappingResults results = inputMapper.map(input, context); - if (results != null && results.hasErrorResults()) { - throw new FlowInputMappingException(getId(), results); - } - } - startActionList.execute(context); - startState.enter(context); - } - - /** - * Resume a paused session for this flow in its current view state. - * @param context the flow execution control context - * @throws FlowExecutionException when an exception occurs during the resume operation - */ - public void resume(RequestControlContext context) throws FlowExecutionException { - restoreVariables(context); - getCurrentViewState(context).resume(context); - } - - /** - * Handle the last event that occurred against an active session of this flow. - * @param context the flow execution control context - */ - public boolean handleEvent(RequestControlContext context) { - TransitionableState currentState = getCurrentTransitionableState(context); - try { - return currentState.handleEvent(context); - } catch (NoMatchingTransitionException e) { - // try the flow level transition set for a match - Transition transition = globalTransitionSet.getTransition(context); - if (transition != null) { - return context.execute(transition); - // return transition.execute(currentState, context); - } else { - // no matching global transition => let the original exception - // propagate - throw e; - } - } - } - - /** - * Inform this flow definition that an execution session of itself has ended. As a result, the flow will do the - * following: - *
    - *
  1. Execute all registered end actions ({@link #getEndActionList()}).
  2. - *
  3. Map data available in the flow execution control context into provided output map using a registered output - * mapper ( {@link #setOutputMapper(Mapper)}).
  4. - *
- * @param context the flow execution control context - * @param outcome the logical flow outcome that will be returned by the session, generally the id of the terminating - * end state - * @param output initial output produced by the session that is eligible for modification by this method - * @throws FlowExecutionException when an exception occurs ending this flow - */ - public void end(RequestControlContext context, String outcome, MutableAttributeMap output) - throws FlowExecutionException { - endActionList.execute(context); - if (outputMapper != null) { - MappingResults results = outputMapper.map(context, output); - if (results != null && results.hasErrorResults()) { - throw new FlowOutputMappingException(getId(), results); - } - } - } - - public void destroy() { - if (applicationContext != null && applicationContext instanceof ConfigurableApplicationContext) { - ((ConfigurableApplicationContext) applicationContext).close(); - } - } - - /** - * Handle an exception that occurred during an execution of this flow. - * @param exception the exception that occurred - * @param context the flow execution control context - */ - public boolean handleException(FlowExecutionException exception, RequestControlContext context) - throws FlowExecutionException { - return getExceptionHandlerSet().handleException(exception, context); - } - - // internal helpers - - private void assertStartStateSet() { - if (startState == null) { - throw new IllegalStateException("Unable to start flow '" + id - + "'; the start state is not set -- flow builder configuration error?"); - } - } - - private void createVariables(RequestContext context) { - for (FlowVariable variable : variables.values()) { - if (logger.isDebugEnabled()) { - logger.debug("Creating " + variable); - } - variable.create(context); - } - } - - public void restoreVariables(RequestContext context) { - for (FlowVariable variable : variables.values()) { - if (logger.isDebugEnabled()) { - logger.debug("Restoring " + variable); - } - variable.restore(context); - } - } - - private ViewState getCurrentViewState(RequestControlContext context) { - State currentState = (State) context.getCurrentState(); - if (!(currentState instanceof ViewState)) { - throw new IllegalStateException("You can only resume paused view states, and state " - + context.getCurrentState() + " is not a view state - programmer error"); - } - return (ViewState) currentState; - } - - private TransitionableState getCurrentTransitionableState(RequestControlContext context) { - State currentState = (State) context.getCurrentState(); - if (!(currentState instanceof TransitionableState)) { - throw new IllegalStateException("You can only signal events in transitionable states, and state " - + context.getCurrentState() + " is not transitionable - programmer error"); - } - return (TransitionableState) currentState; - } - - public String toString() { - return new ToStringCreator(this).append("id", id).append("states", states).append("startState", startState) - .append("variables", variables).append("inputMapper", inputMapper) - .append("startActionList", startActionList).append("exceptionHandlerSet", exceptionHandlerSet) - .append("globalTransitionSet", globalTransitionSet).append("endActionList", endActionList) - .append("outputMapper", outputMapper).toString(); - } - -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.binding.mapping.Mapper; +import org.springframework.binding.mapping.MappingResults; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.style.StylerUtils; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; +import org.springframework.webflow.core.AnnotatedObject; +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.StateDefinition; +import org.springframework.webflow.definition.TransitionDefinition; +import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.execution.RequestContext; + +/** + * A single flow definition. A Flow definition is a reusable, self-contained controller module that provides the blue + * print for a user dialog or conversation. Flows typically drive controlled navigations within web applications to + * guide users through fulfillment of a business process/goal that takes place over a series of steps, modeled as + * states. + *

+ * A simple Flow definition could do nothing more than execute an action and display a view all in one request. A more + * elaborate Flow definition may be long-lived and execute across a series of requests, invoking many possible paths, + * actions, and subflows. + *

+ * Especially in Intranet applications there are often "controlled navigations" where the user is not free to do what he + * or she wants but must follow the guidelines provided by the system to complete a process that is transactional in + * nature (the quintessential example would be a 'checkout' flow of a shopping cart application). This is a typical use + * case appropriate to model as a flow. + *

+ * Structurally a Flow is composed of a set of states. A {@link State} is a point in a flow where a behavior is + * executed; for example, showing a view, executing an action, spawning a subflow, or terminating the flow. Different + * types of states execute different behaviors in a polymorphic fashion. + *

+ * Each {@link TransitionableState} type has one or more transitions that when executed move a flow to another state. + * These transitions define the supported paths through the flow. + *

+ * A state transition is triggered by the occurrence of an event. An event is something that happens the flow should + * respond to, for example a user input event like ("submit") or an action execution result event like ("success"). When + * an event occurs in a state of a Flow that event drives a state transition that decides what to do next. + *

+ * Each Flow has exactly one start state. A start state is simply a marker noting the state executions of this Flow + * definition should start in. The first state added to the flow will become the start state by default. + *

+ * Flow definitions may have one or more flow exception handlers. A {@link FlowExecutionExceptionHandler} can execute + * custom behavior in response to a specific exception (or set of exceptions) that occur in a state of one of this + * flow's executions. + *

+ * Instances of this class are typically built by {@link org.springframework.webflow.engine.builder.FlowBuilder} + * implementations but may also be directly instantiated. + *

+ * This class and the rest of the Spring Web Flow (SWF) engine have been designed with minimal dependencies on other + * libraries. Spring Web Flow is usable in a standalone fashion. The engine system is fully usable outside an HTTP + * servlet environment, for example in tests, or standalone applications. One of the major architectural + * benefits of Spring Web Flow is the ability to design reusable, high-level controller modules that may be executed in + * any environment. + *

+ * Note: flows are singleton definition objects so they should be thread-safe. You can think a flow definition as + * analogous to a Java class, defining all the behavior of an application module. The core behaviors + * {@link #start(RequestControlContext, MutableAttributeMap) start}, {@link #resume(RequestControlContext)}, + * {@link #handleEvent(RequestControlContext) on event}, + * {@link #end(RequestControlContext, String, MutableAttributeMap) end}, and + * {@link #handleException(FlowExecutionException, RequestControlContext)}. Each method accepts a {@link RequestContext + * request context} that allows for this flow to access execution state in a thread safe manner. A flow execution is + * what models a running instance of this flow definition, somewhat analogous to a java object that is an instance of a + * class. + * + * @see org.springframework.webflow.engine.State + * @see org.springframework.webflow.engine.ActionState + * @see org.springframework.webflow.engine.ViewState + * @see org.springframework.webflow.engine.SubflowState + * @see org.springframework.webflow.engine.EndState + * @see org.springframework.webflow.engine.DecisionState + * @see org.springframework.webflow.engine.Transition + * @see org.springframework.webflow.engine.FlowExecutionExceptionHandler + * + * @author Keith Donald + * @author Erwin Vervaet + * @author Colin Sampaleanu + * @author Jeremy Grelle + */ +public class Flow extends AnnotatedObject implements FlowDefinition { + + /** + * Logger, can be used in subclasses. + */ + protected final Log logger = LogFactory.getLog(getClass()); + + /** + * An assigned flow identifier uniquely identifying this flow among all other flows. + */ + private String id; + + /** + * The set of state definitions for this flow. + */ + private Set states = new LinkedHashSet<>(9); + + /** + * The default start state for this flow. + */ + private State startState; + + /** + * The set of flow variables created by this flow. + */ + private Map variables = new LinkedHashMap<>(); + + /** + * The mapper to map flow input attributes. + */ + private Mapper inputMapper; + + /** + * The list of actions to execute when this flow starts. + *

+ * Start actions should execute with care as during startup a flow session has not yet fully initialized and some + * properties like its "currentState" have not yet been set. + */ + private ActionList startActionList = new ActionList(); + + /** + * The set of global transitions that are shared by all states of this flow. + */ + private TransitionSet globalTransitionSet = new TransitionSet(); + + /** + * The list of actions to execute when this flow ends. + */ + private ActionList endActionList = new ActionList(); + + /** + * The mapper to map flow output attributes. + */ + private Mapper outputMapper; + + /** + * The set of exception handlers for this flow. + */ + private FlowExecutionExceptionHandlerSet exceptionHandlerSet = new FlowExecutionExceptionHandlerSet(); + + /** + * An optional application context hosting services needed by this flow. + */ + private ApplicationContext applicationContext; + + /** + * Construct a new flow definition with the given id. The id should be unique among all flows. + * @param id the flow identifier + */ + public Flow(String id) { + Assert.hasText(id, "This flow must be uniquely identified"); + this.id = id; + } + + // convenient static factory methods + + /** + * Create a new flow with the given id and attributes. + * @param id the flow id + * @param attributes the attributes + * @return the flow + */ + public static Flow create(String id, AttributeMap attributes) { + Flow flow = new Flow(id); + flow.getAttributes().putAll(attributes); + return flow; + } + + // implementing FlowDefinition + + public String getId() { + return id; + } + + public StateDefinition getStartState() { + if (startState == null) { + throw new IllegalStateException("No start state has been set for this flow ('" + getId() + + "') -- flow builder configuration error?"); + } + return startState; + } + + public StateDefinition getState(String stateId) { + return getStateInstance(stateId); + } + + public String[] getPossibleOutcomes() { + List possibleOutcomes = new ArrayList<>(); + for (State state : states) { + if (state instanceof EndState) { + possibleOutcomes.add(state.getId()); + } + } + return possibleOutcomes.toArray(new String[possibleOutcomes.size()]); + } + + public ClassLoader getClassLoader() { + if (applicationContext != null) { + return applicationContext.getClassLoader(); + } else { + return ClassUtils.getDefaultClassLoader(); + } + } + + public ApplicationContext getApplicationContext() { + return applicationContext; + } + + public boolean inDevelopment() { + return getAttributes().getBoolean("development", false); + } + + /** + * Add given state definition to this flow definition. Marked protected, as this method is to be called by the + * (privileged) state definition classes themselves during state construction as part of a FlowBuilder invocation. + * @param state the state to add + * @throws IllegalArgumentException when the state cannot be added to the flow; for instance if another state shares + * the same id as the one provided or if given state already belongs to another flow + */ + protected void add(State state) throws IllegalArgumentException { + if (this != state.getFlow() && state.getFlow() != null) { + throw new IllegalArgumentException("State " + state + " cannot be added to this flow '" + getId() + + "' -- it already belongs to a different flow: '" + state.getFlow().getId() + "'"); + } + if (this.states.contains(state) || this.containsState(state.getId())) { + throw new IllegalArgumentException("This flow '" + getId() + "' already contains a state with id '" + + state.getId() + "' -- state ids must be locally unique to the flow definition; " + + "existing state-ids of this flow include: " + StylerUtils.style(getStateIds())); + } + boolean firstAdd = states.isEmpty(); + states.add(state); + if (firstAdd) { + setStartState(state); + } + } + + /** + * Returns the number of states defined in this flow. + * @return the state count + */ + public int getStateCount() { + return states.size(); + } + + /** + * Is a state with the provided id present in this flow? + * @param stateId the state id + * @return true if yes, false otherwise + */ + public boolean containsState(String stateId) { + for (State state : states) { + if (state.getId().equals(stateId)) { + return true; + } + } + return false; + } + + /** + * Set the start state for this flow to the state with the provided stateId; a state must exist by the + * provided stateId. + * @param stateId the id of the new start state + * @throws IllegalArgumentException when no state exists with the id you provided + */ + public void setStartState(String stateId) throws IllegalArgumentException { + setStartState(getStateInstance(stateId)); + } + + /** + * Set the start state for this flow to the state provided; any state may be the start state. + * @param state the new start state + * @throws IllegalArgumentException given state has not been added to this flow + */ + public void setStartState(State state) throws IllegalArgumentException { + if (!states.contains(state)) { + throw new IllegalArgumentException("State '" + state + "' is not a state of flow '" + getId() + "'"); + } + startState = state; + } + + /** + * Return the TransitionableState with given stateId. + * @param stateId id of the state to look up + * @return the transitionable state + * @throws IllegalArgumentException if the identified state cannot be found + * @throws ClassCastException when the identified state is not transitionable + */ + public TransitionableState getTransitionableState(String stateId) throws IllegalArgumentException, + ClassCastException { + State state = getStateInstance(stateId); + if (state != null && !(state instanceof TransitionableState)) { + throw new ClassCastException("The state '" + stateId + "' of flow '" + getId() + "' must be transitionable"); + } + return (TransitionableState) state; + } + + /** + * Lookup the identified state instance of this flow. + * @param stateId the state id + * @return the state + * @throws IllegalArgumentException if the identified state cannot be found + */ + public State getStateInstance(String stateId) throws IllegalArgumentException { + if (!StringUtils.hasText(stateId)) { + throw new IllegalArgumentException("The specified stateId is invalid: state identifiers must be non-blank"); + } + for (State state : states) { + if (state.getId().equals(stateId)) { + return state; + } + } + throw new IllegalArgumentException("Cannot find state with id '" + stateId + "' in flow '" + getId() + "' -- " + + "Known state ids are '" + StylerUtils.style(getStateIds()) + "'"); + } + + /** + * Convenience accessor that returns an ordered array of the String ids for the state definitions + * associated with this flow definition. + * @return the state ids + */ + public String[] getStateIds() { + String[] stateIds = new String[getStateCount()]; + int i = 0; + for (State state : states) { + stateIds[i++] = state.getId(); + } + return stateIds; + } + + /** + * Adds a flow variable. + * @param variable the variable + */ + public void addVariable(FlowVariable variable) { + variables.put(variable.getName(), variable); + } + + /** + * Adds flow variables. + * @param variables the variables + */ + public void addVariables(FlowVariable... variables) { + if (variables == null) { + return; + } + for (FlowVariable variable : variables) { + addVariable(variable); + } + } + + /** + * Returns the flow variable with the given name. + * @param name the name of the variable + */ + public FlowVariable getVariable(String name) { + return variables.get(name); + } + + /** + * Returns the flow variables. + */ + public FlowVariable[] getVariables() { + return variables.values().toArray(new FlowVariable[variables.size()]); + } + + /** + * Returns the configured flow input mapper, or null if none. + * @return the input mapper + */ + public Mapper getInputMapper() { + return inputMapper; + } + + /** + * Sets the mapper to map flow input attributes. + * @param inputMapper the input mapper + */ + public void setInputMapper(Mapper inputMapper) { + this.inputMapper = inputMapper; + } + + /** + * Returns the list of actions executed by this flow when an execution of the flow starts. The returned list + * is mutable. + * @return the start action list + */ + public ActionList getStartActionList() { + return startActionList; + } + + /** + * Returns the list of actions executed by this flow when an execution of the flow ends. The returned list is + * mutable. + * @return the end action list + */ + public ActionList getEndActionList() { + return endActionList; + } + + /** + * Returns the configured flow output mapper, or null if none. + * @return the output mapper + */ + public Mapper getOutputMapper() { + return outputMapper; + } + + /** + * Sets the mapper to map flow output attributes. + * @param outputMapper the output mapper + */ + public void setOutputMapper(Mapper outputMapper) { + this.outputMapper = outputMapper; + } + + /** + * Returns the set of exception handlers, allowing manipulation of how exceptions are handled when thrown during + * flow execution. Exception handlers are invoked when an exception occurs at execution time and can execute custom + * exception handling logic as well as select an error view to display. Exception handlers attached at the flow + * level have an opportunity to handle exceptions that aren't handled at the state level. + * @return the exception handler set + */ + public FlowExecutionExceptionHandlerSet getExceptionHandlerSet() { + return exceptionHandlerSet; + } + + /** + * Returns the set of transitions eligible for execution by this flow if no state-level transition is matched. The + * returned set is mutable. + * @return the global transition set + */ + public TransitionSet getGlobalTransitionSet() { + return globalTransitionSet; + } + + /** + * Returns the transition that matches the event with the provided id. + * @param eventId the event id + * @return the transition that matches, or null if no match is found. + */ + public TransitionDefinition getGlobalTransition(String eventId) { + for (Transition transition : globalTransitionSet) { + if (transition.getId().equals(eventId)) { + return transition; + } + } + return null; + } + + /** + * Sets a reference to the application context hosting application objects needed by this flow. + * @param applicationContext the application context + */ + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + // id based equality + + public boolean equals(Object o) { + if (!(o instanceof Flow)) { + return false; + } + Flow other = (Flow) o; + return id.equals(other.id); + } + + public int hashCode() { + return id.hashCode(); + } + + // behavioral code, could be overridden in subclasses + + /** + * Start a new session for this flow in its start state. This boils down to the following: + *

    + *
  1. Create (setup) all registered flow variables ({@link #addVariable(FlowVariable)}) in flow scope.
  2. + *
  3. Map provided input data into the flow. Typically data will be mapped into flow scope using the registered + * input mapper ({@link #setInputMapper(Mapper)}).
  4. + *
  5. Execute all registered start actions ( {@link #getStartActionList()}).
  6. + *
  7. Enter the configured start state ({@link #setStartState(State)})
  8. + *
+ * @param context the flow execution control context + * @param input eligible input into the session + * @throws FlowExecutionException when an exception occurs starting the flow + */ + public void start(RequestControlContext context, MutableAttributeMap input) throws FlowExecutionException { + assertStartStateSet(); + createVariables(context); + if (inputMapper != null) { + MappingResults results = inputMapper.map(input, context); + if (results != null && results.hasErrorResults()) { + throw new FlowInputMappingException(getId(), results); + } + } + startActionList.execute(context); + startState.enter(context); + } + + /** + * Resume a paused session for this flow in its current view state. + * @param context the flow execution control context + * @throws FlowExecutionException when an exception occurs during the resume operation + */ + public void resume(RequestControlContext context) throws FlowExecutionException { + restoreVariables(context); + getCurrentViewState(context).resume(context); + } + + /** + * Handle the last event that occurred against an active session of this flow. + * @param context the flow execution control context + */ + public boolean handleEvent(RequestControlContext context) { + TransitionableState currentState = getCurrentTransitionableState(context); + try { + return currentState.handleEvent(context); + } catch (NoMatchingTransitionException e) { + // try the flow level transition set for a match + Transition transition = globalTransitionSet.getTransition(context); + if (transition != null) { + return context.execute(transition); + // return transition.execute(currentState, context); + } else { + // no matching global transition => let the original exception + // propagate + throw e; + } + } + } + + /** + * Inform this flow definition that an execution session of itself has ended. As a result, the flow will do the + * following: + *
    + *
  1. Execute all registered end actions ({@link #getEndActionList()}).
  2. + *
  3. Map data available in the flow execution control context into provided output map using a registered output + * mapper ( {@link #setOutputMapper(Mapper)}).
  4. + *
+ * @param context the flow execution control context + * @param outcome the logical flow outcome that will be returned by the session, generally the id of the terminating + * end state + * @param output initial output produced by the session that is eligible for modification by this method + * @throws FlowExecutionException when an exception occurs ending this flow + */ + public void end(RequestControlContext context, String outcome, MutableAttributeMap output) + throws FlowExecutionException { + endActionList.execute(context); + if (outputMapper != null) { + MappingResults results = outputMapper.map(context, output); + if (results != null && results.hasErrorResults()) { + throw new FlowOutputMappingException(getId(), results); + } + } + } + + public void destroy() { + if (applicationContext != null && applicationContext instanceof ConfigurableApplicationContext) { + ((ConfigurableApplicationContext) applicationContext).close(); + } + } + + /** + * Handle an exception that occurred during an execution of this flow. + * @param exception the exception that occurred + * @param context the flow execution control context + */ + public boolean handleException(FlowExecutionException exception, RequestControlContext context) + throws FlowExecutionException { + return getExceptionHandlerSet().handleException(exception, context); + } + + // internal helpers + + private void assertStartStateSet() { + if (startState == null) { + throw new IllegalStateException("Unable to start flow '" + id + + "'; the start state is not set -- flow builder configuration error?"); + } + } + + private void createVariables(RequestContext context) { + for (FlowVariable variable : variables.values()) { + if (logger.isDebugEnabled()) { + logger.debug("Creating " + variable); + } + variable.create(context); + } + } + + public void restoreVariables(RequestContext context) { + for (FlowVariable variable : variables.values()) { + if (logger.isDebugEnabled()) { + logger.debug("Restoring " + variable); + } + variable.restore(context); + } + } + + private ViewState getCurrentViewState(RequestControlContext context) { + State currentState = (State) context.getCurrentState(); + if (!(currentState instanceof ViewState)) { + throw new IllegalStateException("You can only resume paused view states, and state " + + context.getCurrentState() + " is not a view state - programmer error"); + } + return (ViewState) currentState; + } + + private TransitionableState getCurrentTransitionableState(RequestControlContext context) { + State currentState = (State) context.getCurrentState(); + if (!(currentState instanceof TransitionableState)) { + throw new IllegalStateException("You can only signal events in transitionable states, and state " + + context.getCurrentState() + " is not transitionable - programmer error"); + } + return (TransitionableState) currentState; + } + + public String toString() { + return new ToStringCreator(this).append("id", id).append("states", states).append("startState", startState) + .append("variables", variables).append("inputMapper", inputMapper) + .append("startActionList", startActionList).append("exceptionHandlerSet", exceptionHandlerSet) + .append("globalTransitionSet", globalTransitionSet).append("endActionList", endActionList) + .append("outputMapper", outputMapper).toString(); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowExecutionExceptionHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowExecutionExceptionHandler.java index 9c8fd207..c4644ec2 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowExecutionExceptionHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowExecutionExceptionHandler.java @@ -1,55 +1,55 @@ -/* - * 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 - * - * https://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.engine; - -import org.springframework.webflow.execution.FlowExecutionException; - -/** - * A strategy for handling an exception that occurs at runtime during an active flow execution. - * - * Note: special care should be taken when implementing custom flow execution exception handlers. Exception handlers are - * like Transitions in that they direct flow control when exceptions occur. They are more complex than Actions, which - * can only execute behaviors and return results that drive flow control. For this reason, if implemented incorrectly, a - * FlowExecutionHandler can leave a flow execution in an invalid state, which can render the flow execution unusable or - * its future use undefined. For example, if an exception thrown at flow session startup gets routed to an exception - * handler, the handler must take responsibility for ensuring the flow execution returns control to the caller in a - * consistent state. Concretely, this means the exception handler must transition the flow to its start state. The - * handler should not simply return leaving the flow with no current state set. - * - * Note: Because flow execution handlers are more difficult to implement correctly, consider catching exceptions in your - * web flow action code and returning result events that drive standard transitions. Alternatively, consider use of the - * existing {@code TransitionExecutingFlowExecutionExceptionHandler} which illustrates the proper way to implement an - * exception handler. - * - * @author Keith Donald - */ -public interface FlowExecutionExceptionHandler { - - /** - * Can this handler handle the given exception? - * @param exception the exception that occurred - * @return true if yes, false if no - */ - boolean canHandle(FlowExecutionException exception); - - /** - * Handle the exception in the context of the current request. An implementation is expected to transition the flow - * to a state using {@link RequestControlContext#execute(Transition)}. - * @param exception the exception that occurred - * @param context the execution control context for this request - */ - void handle(FlowExecutionException exception, RequestControlContext context); -} +/* + * 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 + * + * https://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.engine; + +import org.springframework.webflow.execution.FlowExecutionException; + +/** + * A strategy for handling an exception that occurs at runtime during an active flow execution. + * + * Note: special care should be taken when implementing custom flow execution exception handlers. Exception handlers are + * like Transitions in that they direct flow control when exceptions occur. They are more complex than Actions, which + * can only execute behaviors and return results that drive flow control. For this reason, if implemented incorrectly, a + * FlowExecutionHandler can leave a flow execution in an invalid state, which can render the flow execution unusable or + * its future use undefined. For example, if an exception thrown at flow session startup gets routed to an exception + * handler, the handler must take responsibility for ensuring the flow execution returns control to the caller in a + * consistent state. Concretely, this means the exception handler must transition the flow to its start state. The + * handler should not simply return leaving the flow with no current state set. + * + * Note: Because flow execution handlers are more difficult to implement correctly, consider catching exceptions in your + * web flow action code and returning result events that drive standard transitions. Alternatively, consider use of the + * existing {@code TransitionExecutingFlowExecutionExceptionHandler} which illustrates the proper way to implement an + * exception handler. + * + * @author Keith Donald + */ +public interface FlowExecutionExceptionHandler { + + /** + * Can this handler handle the given exception? + * @param exception the exception that occurred + * @return true if yes, false if no + */ + boolean canHandle(FlowExecutionException exception); + + /** + * Handle the exception in the context of the current request. An implementation is expected to transition the flow + * to a state using {@link RequestControlContext#execute(Transition)}. + * @param exception the exception that occurred + * @param context the execution control context for this request + */ + void handle(FlowExecutionException exception, RequestControlContext context); +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowExecutionExceptionHandlerSet.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowExecutionExceptionHandlerSet.java index a25d949f..6decc5af 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowExecutionExceptionHandlerSet.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowExecutionExceptionHandlerSet.java @@ -1,119 +1,119 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import java.util.LinkedList; -import java.util.List; - -import org.springframework.core.style.StylerUtils; -import org.springframework.webflow.core.collection.CollectionUtils; -import org.springframework.webflow.execution.FlowExecutionException; - -/** - * A typed set of state exception handlers, mainly for use internally by artifacts that can apply state exception - * handling logic. - * - * @see FlowExecutionExceptionHandler - * @see Flow#getExceptionHandlerSet() - * @see State#getExceptionHandlerSet() - * - * @author Keith Donald - */ -public class FlowExecutionExceptionHandlerSet { - - /** - * The set of exception handlers. - */ - private List exceptionHandlers = new LinkedList<>(); - - /** - * Add a state exception handler to this set. - * @param exceptionHandler the exception handler to add - * @return true if this set's contents changed as a result of the add operation - */ - public boolean add(FlowExecutionExceptionHandler exceptionHandler) { - if (contains(exceptionHandler)) { - return false; - } - return exceptionHandlers.add(exceptionHandler); - } - - /** - * Add a collection of state exception handler instances to this set. - * @param exceptionHandlers the exception handlers to add - * @return true if this set's contents changed as a result of the add operation - */ - public boolean addAll(FlowExecutionExceptionHandler... exceptionHandlers) { - return CollectionUtils.addAllNoDuplicates(this.exceptionHandlers, exceptionHandlers); - } - - /** - * Tests if this state exception handler is in this set. - * @param exceptionHandler the exception handler - * @return true if the state exception handler is contained in this set, false otherwise - */ - public boolean contains(FlowExecutionExceptionHandler exceptionHandler) { - return exceptionHandlers.contains(exceptionHandler); - } - - /** - * Remove the exception handler instance from this set. - * @param exceptionHandler the exception handler to add - * @return true if this set's contents changed as a result of the remove operation - */ - public boolean remove(FlowExecutionExceptionHandler exceptionHandler) { - return exceptionHandlers.remove(exceptionHandler); - } - - /** - * Returns the size of this state exception handler set. - * @return the exception handler set size - */ - public int size() { - return exceptionHandlers.size(); - } - - /** - * Convert this list to a typed state exception handler array. - * @return the exception handler list, as a typed array - */ - public FlowExecutionExceptionHandler[] toArray() { - return exceptionHandlers.toArray(new FlowExecutionExceptionHandler[exceptionHandlers.size()]); - } - - /** - * Handle an exception that occurred during the context of the current flow execution request. - *

- * This implementation iterates over the ordered set of exception handler objects, delegating to each handler in the - * set until one handles the exception that occurred. - * @param exception the exception that occurred - * @param context the flow execution control context - * @return true if the exception was handled - */ - public boolean handleException(FlowExecutionException exception, RequestControlContext context) { - for (FlowExecutionExceptionHandler handler : exceptionHandlers) { - if (handler.canHandle(exception)) { - handler.handle(exception, context); - return true; - } - } - return false; - } - - public String toString() { - return StylerUtils.style(exceptionHandlers); - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.core.style.StylerUtils; +import org.springframework.webflow.core.collection.CollectionUtils; +import org.springframework.webflow.execution.FlowExecutionException; + +/** + * A typed set of state exception handlers, mainly for use internally by artifacts that can apply state exception + * handling logic. + * + * @see FlowExecutionExceptionHandler + * @see Flow#getExceptionHandlerSet() + * @see State#getExceptionHandlerSet() + * + * @author Keith Donald + */ +public class FlowExecutionExceptionHandlerSet { + + /** + * The set of exception handlers. + */ + private List exceptionHandlers = new LinkedList<>(); + + /** + * Add a state exception handler to this set. + * @param exceptionHandler the exception handler to add + * @return true if this set's contents changed as a result of the add operation + */ + public boolean add(FlowExecutionExceptionHandler exceptionHandler) { + if (contains(exceptionHandler)) { + return false; + } + return exceptionHandlers.add(exceptionHandler); + } + + /** + * Add a collection of state exception handler instances to this set. + * @param exceptionHandlers the exception handlers to add + * @return true if this set's contents changed as a result of the add operation + */ + public boolean addAll(FlowExecutionExceptionHandler... exceptionHandlers) { + return CollectionUtils.addAllNoDuplicates(this.exceptionHandlers, exceptionHandlers); + } + + /** + * Tests if this state exception handler is in this set. + * @param exceptionHandler the exception handler + * @return true if the state exception handler is contained in this set, false otherwise + */ + public boolean contains(FlowExecutionExceptionHandler exceptionHandler) { + return exceptionHandlers.contains(exceptionHandler); + } + + /** + * Remove the exception handler instance from this set. + * @param exceptionHandler the exception handler to add + * @return true if this set's contents changed as a result of the remove operation + */ + public boolean remove(FlowExecutionExceptionHandler exceptionHandler) { + return exceptionHandlers.remove(exceptionHandler); + } + + /** + * Returns the size of this state exception handler set. + * @return the exception handler set size + */ + public int size() { + return exceptionHandlers.size(); + } + + /** + * Convert this list to a typed state exception handler array. + * @return the exception handler list, as a typed array + */ + public FlowExecutionExceptionHandler[] toArray() { + return exceptionHandlers.toArray(new FlowExecutionExceptionHandler[exceptionHandlers.size()]); + } + + /** + * Handle an exception that occurred during the context of the current flow execution request. + *

+ * This implementation iterates over the ordered set of exception handler objects, delegating to each handler in the + * set until one handles the exception that occurred. + * @param exception the exception that occurred + * @param context the flow execution control context + * @return true if the exception was handled + */ + public boolean handleException(FlowExecutionException exception, RequestControlContext context) { + for (FlowExecutionExceptionHandler handler : exceptionHandlers) { + if (handler.canHandle(exception)) { + handler.handle(exception, context); + return true; + } + } + return false; + } + + public String toString() { + return StylerUtils.style(exceptionHandlers); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java index 344d073d..edf183fa 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/FlowVariable.java @@ -1,104 +1,104 @@ -/* - * 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 - * - * https://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.engine; - -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.webflow.core.AnnotatedObject; -import org.springframework.webflow.execution.RequestContext; - -/** - * A value object that defines a specification for a flow variable. Such a variable is allocated when a flow starts and - * destroyed when that flow ends. This class encapsulates information about the variable and the behavior necessary to - * allocate the variable instance in flow scope. - * - * @author Keith Donald - */ -public class FlowVariable extends AnnotatedObject { - - /** - * The variable name. - */ - private String name; - - /** - * The value factory that provides this variable's value. - */ - private VariableValueFactory valueFactory; - - /** - * Creates a new flow variable. - * @param name the variable name - */ - public FlowVariable(String name, VariableValueFactory valueFactory) { - Assert.hasText(name, "The variable name is required"); - Assert.notNull(valueFactory, "The variable value factory is required"); - this.name = name; - this.valueFactory = valueFactory; - } - - /** - * Returns the name of this variable. - */ - public String getName() { - return name; - } - - // name and scope based equality - - public boolean equals(Object o) { - if (!(o instanceof FlowVariable)) { - return false; - } - FlowVariable other = (FlowVariable) o; - return name.equals(other.name) && valueFactory.equals(other.valueFactory); - } - - public int hashCode() { - return name.hashCode() + valueFactory.hashCode(); - } - - /** - * Creates this flow variable. This method allocates the variable's value in the correct flow scope. - * @param context the executing flow - */ - public void create(RequestContext context) { - Object value = valueFactory.createInitialValue(context); - context.getFlowScope().put(name, value); - } - - /** - * Restores this variable's dependencies. This method asks the variable's value factory to restore any references - * the variable has to transient objects. - * @param context the executing flow - */ - public void restore(RequestContext context) { - Object value = context.getFlowScope().get(name); - valueFactory.restoreReferences(value, context); - } - - /** - * Destroys this flow variable. This method removes the variable's value in the correct flow scope. - * @param context the executing flow - */ - public Object destroy(RequestContext context) { - return context.getFlowScope().remove(name); - } - - public String toString() { - return new ToStringCreator(this).append("name", name).append("valueFactory", valueFactory).toString(); - } +/* + * 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 + * + * https://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.engine; + +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.webflow.core.AnnotatedObject; +import org.springframework.webflow.execution.RequestContext; + +/** + * A value object that defines a specification for a flow variable. Such a variable is allocated when a flow starts and + * destroyed when that flow ends. This class encapsulates information about the variable and the behavior necessary to + * allocate the variable instance in flow scope. + * + * @author Keith Donald + */ +public class FlowVariable extends AnnotatedObject { + + /** + * The variable name. + */ + private String name; + + /** + * The value factory that provides this variable's value. + */ + private VariableValueFactory valueFactory; + + /** + * Creates a new flow variable. + * @param name the variable name + */ + public FlowVariable(String name, VariableValueFactory valueFactory) { + Assert.hasText(name, "The variable name is required"); + Assert.notNull(valueFactory, "The variable value factory is required"); + this.name = name; + this.valueFactory = valueFactory; + } + + /** + * Returns the name of this variable. + */ + public String getName() { + return name; + } + + // name and scope based equality + + public boolean equals(Object o) { + if (!(o instanceof FlowVariable)) { + return false; + } + FlowVariable other = (FlowVariable) o; + return name.equals(other.name) && valueFactory.equals(other.valueFactory); + } + + public int hashCode() { + return name.hashCode() + valueFactory.hashCode(); + } + + /** + * Creates this flow variable. This method allocates the variable's value in the correct flow scope. + * @param context the executing flow + */ + public void create(RequestContext context) { + Object value = valueFactory.createInitialValue(context); + context.getFlowScope().put(name, value); + } + + /** + * Restores this variable's dependencies. This method asks the variable's value factory to restore any references + * the variable has to transient objects. + * @param context the executing flow + */ + public void restore(RequestContext context) { + Object value = context.getFlowScope().get(name); + valueFactory.restoreReferences(value, context); + } + + /** + * Destroys this flow variable. This method removes the variable's value in the correct flow scope. + * @param context the executing flow + */ + public Object destroy(RequestContext context) { + return context.getFlowScope().remove(name); + } + + public String toString() { + return new ToStringCreator(this).append("name", name).append("valueFactory", valueFactory).toString(); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/NoMatchingTransitionException.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/NoMatchingTransitionException.java index 6a6c46e6..26a24c4d 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/NoMatchingTransitionException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/NoMatchingTransitionException.java @@ -1,67 +1,67 @@ -/* - * 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 - * - * https://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.engine; - -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.FlowExecutionException; - -/** - * Thrown when no transition can be matched given the occurence of an event in the context of a flow execution request. - *

- * Typically this happens because there is no "handler" transition for the last event that occured. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class NoMatchingTransitionException extends FlowExecutionException { - - /** - * The event that occurred that could not be matched to a Transition. - */ - private Event event; - - /** - * Create a new no matching transition exception. - * @param flowId the current flow - * @param stateId the state that could not be transitioned out of - * @param event the event that occured that could not be matched to a transition - * @param message the message - */ - public NoMatchingTransitionException(String flowId, String stateId, Event event, String message) { - super(flowId, stateId, message); - this.event = event; - } - - /** - * Create a new no matching transition exception. - * @param flowId the current flow - * @param stateId the state that could not be transitioned out of - * @param event the event that occured that could not be matched to a transition - * @param message the message - * @param cause the underlying cause - */ - public NoMatchingTransitionException(String flowId, String stateId, Event event, String message, Throwable cause) { - super(flowId, stateId, message, cause); - this.event = event; - } - - /** - * Returns the event for the current request that did not trigger any supported transition. - */ - public Event getEvent() { - return event; - } +/* + * 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 + * + * https://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.engine; + +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.execution.FlowExecutionException; + +/** + * Thrown when no transition can be matched given the occurence of an event in the context of a flow execution request. + *

+ * Typically this happens because there is no "handler" transition for the last event that occured. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class NoMatchingTransitionException extends FlowExecutionException { + + /** + * The event that occurred that could not be matched to a Transition. + */ + private Event event; + + /** + * Create a new no matching transition exception. + * @param flowId the current flow + * @param stateId the state that could not be transitioned out of + * @param event the event that occured that could not be matched to a transition + * @param message the message + */ + public NoMatchingTransitionException(String flowId, String stateId, Event event, String message) { + super(flowId, stateId, message); + this.event = event; + } + + /** + * Create a new no matching transition exception. + * @param flowId the current flow + * @param stateId the state that could not be transitioned out of + * @param event the event that occured that could not be matched to a transition + * @param message the message + * @param cause the underlying cause + */ + public NoMatchingTransitionException(String flowId, String stateId, Event event, String message, Throwable cause) { + super(flowId, stateId, message, cause); + this.event = event; + } + + /** + * Returns the event for the current request that did not trigger any supported transition. + */ + public Event getEvent() { + return event; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/RequestControlContext.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/RequestControlContext.java index 321e45fa..8291992c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/RequestControlContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/RequestControlContext.java @@ -1,166 +1,166 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.FlowExecutionContext; -import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.execution.FlowExecutionKey; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.View; - -/** - * Mutable control interface used to manipulate an ongoing flow execution in the context of one client request. - * Primarily used internally by the various flow artifacts when they are invoked. - *

- * This interface acts as a facade for core definition constructs such as the central Flow and - * State classes, abstracting away details about the runtime execution machine. - *

- * Note this type is not the same as the {@link FlowExecutionContext}. Objects of this type are request specific: - * they provide a control interface for manipulating exactly one flow execution locally from exactly one request. A - * FlowExecutionContext provides information about a single flow execution (conversation), and it's scope - * is not local to a specific request (or thread). - * - * @see org.springframework.webflow.engine.Flow - * @see org.springframework.webflow.engine.State - * @see org.springframework.webflow.execution.FlowExecution - * @see FlowExecutionContext - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface RequestControlContext extends RequestContext { - - /** - * Record the current state that has entered in the executing flow. This method will be called as part of entering a - * new state by the State type itself. - * @param state the current state - * @see State#enter(RequestControlContext) - */ - void setCurrentState(State state); - - /** - * Assign the ongoing flow execution its flow execution key. This method will be called before a state is about to - * render a view and pause the flow execution. - */ - FlowExecutionKey assignFlowExecutionKey(); - - /** - * Sets the current view. - * @param view the current view, or null to mark the current view as null - */ - void setCurrentView(View view); - - /** - * Called when the current view is about to be rendered in the current view state. - * @param view the view to be rendered - */ - void viewRendering(View view); - - /** - * Called when the current view has completed rendering in the current view state. - * @param view the view that rendered - */ - void viewRendered(View view); - - /** - * Signals the occurrence of an event in the current state of this flow execution request context. This method - * should be called by clients that report internal event occurrences, such as action states. The - * onEvent() method of the flow involved in the flow execution will be called. - * @param event the event that occurred - * @return a boolean indicating if handling this event caused the current state to exit and a new state to enter - * @throws FlowExecutionException if an exception was thrown within a state of the flow during execution of this - * signalEvent operation - * @see Flow#handleEvent(RequestControlContext) - */ - boolean handleEvent(Event event) throws FlowExecutionException; - - /** - * Execute this transition out of the current source state. Allows for privileged execution of an arbitrary - * transition. - * @param transition the transition - * @see Transition#execute(State, RequestControlContext) - */ - boolean execute(Transition transition); - - /** - * Record the transition executing in the flow. This method will be called as part of executing a transition from - * one state to another. - * @param transition the transition being executed - * @see Transition#execute(State, RequestControlContext) - */ - void setCurrentTransition(Transition transition); - - /** - * Update the current flow execution snapshot to save the current state. - */ - void updateCurrentFlowExecutionSnapshot(); - - /** - * Remove the current flow execution snapshot to invalidate the current state. - */ - void removeCurrentFlowExecutionSnapshot(); - - /** - * Remove all flow execution snapshots associated with the ongoing conversation. Invalidates previous states. - */ - void removeAllFlowExecutionSnapshots(); - - /** - * Spawn a new flow session and activate it in the currently executing flow. Also transitions the spawned flow to - * its start state. This method should be called by clients that wish to spawn new flows, such as subflow states. - *

- * This will start a new flow session in the current flow execution, which is already active. - * @param flow the flow to start, its start() method will be called - * @param input initial contents of the newly created flow session (may be null, e.g. empty) - * @throws FlowExecutionException if an exception was thrown within a state of the flow during execution of this - * start operation - * @see Flow#start(RequestControlContext, MutableAttributeMap) - */ - void start(Flow flow, MutableAttributeMap input) throws FlowExecutionException; - - /** - * End the active flow session of the current flow execution. This method should be called by clients that terminate - * flows, such as end states. The end() method of the flow involved in the flow execution will be - * called. - * @param outcome the logical outcome the ending session should return - * @param output output the ending session should return - * @throws IllegalStateException when the flow execution is not active - * @see Flow#end(RequestControlContext, String, MutableAttributeMap) - */ - void endActiveFlowSession(String outcome, MutableAttributeMap output) throws IllegalStateException; - - /** - * Returns true if the 'redirect on pause' flow execution attribute is set to true, false otherwise. - * @return true or false - */ - boolean getRedirectOnPause(); - - /** - * Returns the value of the 'redirect in same state' flow execution attribute if set or otherwise it falls back on - * the value returned by {@link #getRedirectOnPause()}. - * @return true or false - */ - boolean getRedirectInSameState(); - - /** - * Returns true if the flow current flow execution was launched in embedded page mode. When a flow is embedded on a - * page it can make different assumptions with regards to whether redirect after post is necessary. - */ - boolean getEmbeddedMode(); - -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.execution.FlowExecutionContext; +import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.execution.FlowExecutionKey; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.View; + +/** + * Mutable control interface used to manipulate an ongoing flow execution in the context of one client request. + * Primarily used internally by the various flow artifacts when they are invoked. + *

+ * This interface acts as a facade for core definition constructs such as the central Flow and + * State classes, abstracting away details about the runtime execution machine. + *

+ * Note this type is not the same as the {@link FlowExecutionContext}. Objects of this type are request specific: + * they provide a control interface for manipulating exactly one flow execution locally from exactly one request. A + * FlowExecutionContext provides information about a single flow execution (conversation), and it's scope + * is not local to a specific request (or thread). + * + * @see org.springframework.webflow.engine.Flow + * @see org.springframework.webflow.engine.State + * @see org.springframework.webflow.execution.FlowExecution + * @see FlowExecutionContext + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface RequestControlContext extends RequestContext { + + /** + * Record the current state that has entered in the executing flow. This method will be called as part of entering a + * new state by the State type itself. + * @param state the current state + * @see State#enter(RequestControlContext) + */ + void setCurrentState(State state); + + /** + * Assign the ongoing flow execution its flow execution key. This method will be called before a state is about to + * render a view and pause the flow execution. + */ + FlowExecutionKey assignFlowExecutionKey(); + + /** + * Sets the current view. + * @param view the current view, or null to mark the current view as null + */ + void setCurrentView(View view); + + /** + * Called when the current view is about to be rendered in the current view state. + * @param view the view to be rendered + */ + void viewRendering(View view); + + /** + * Called when the current view has completed rendering in the current view state. + * @param view the view that rendered + */ + void viewRendered(View view); + + /** + * Signals the occurrence of an event in the current state of this flow execution request context. This method + * should be called by clients that report internal event occurrences, such as action states. The + * onEvent() method of the flow involved in the flow execution will be called. + * @param event the event that occurred + * @return a boolean indicating if handling this event caused the current state to exit and a new state to enter + * @throws FlowExecutionException if an exception was thrown within a state of the flow during execution of this + * signalEvent operation + * @see Flow#handleEvent(RequestControlContext) + */ + boolean handleEvent(Event event) throws FlowExecutionException; + + /** + * Execute this transition out of the current source state. Allows for privileged execution of an arbitrary + * transition. + * @param transition the transition + * @see Transition#execute(State, RequestControlContext) + */ + boolean execute(Transition transition); + + /** + * Record the transition executing in the flow. This method will be called as part of executing a transition from + * one state to another. + * @param transition the transition being executed + * @see Transition#execute(State, RequestControlContext) + */ + void setCurrentTransition(Transition transition); + + /** + * Update the current flow execution snapshot to save the current state. + */ + void updateCurrentFlowExecutionSnapshot(); + + /** + * Remove the current flow execution snapshot to invalidate the current state. + */ + void removeCurrentFlowExecutionSnapshot(); + + /** + * Remove all flow execution snapshots associated with the ongoing conversation. Invalidates previous states. + */ + void removeAllFlowExecutionSnapshots(); + + /** + * Spawn a new flow session and activate it in the currently executing flow. Also transitions the spawned flow to + * its start state. This method should be called by clients that wish to spawn new flows, such as subflow states. + *

+ * This will start a new flow session in the current flow execution, which is already active. + * @param flow the flow to start, its start() method will be called + * @param input initial contents of the newly created flow session (may be null, e.g. empty) + * @throws FlowExecutionException if an exception was thrown within a state of the flow during execution of this + * start operation + * @see Flow#start(RequestControlContext, MutableAttributeMap) + */ + void start(Flow flow, MutableAttributeMap input) throws FlowExecutionException; + + /** + * End the active flow session of the current flow execution. This method should be called by clients that terminate + * flows, such as end states. The end() method of the flow involved in the flow execution will be + * called. + * @param outcome the logical outcome the ending session should return + * @param output output the ending session should return + * @throws IllegalStateException when the flow execution is not active + * @see Flow#end(RequestControlContext, String, MutableAttributeMap) + */ + void endActiveFlowSession(String outcome, MutableAttributeMap output) throws IllegalStateException; + + /** + * Returns true if the 'redirect on pause' flow execution attribute is set to true, false otherwise. + * @return true or false + */ + boolean getRedirectOnPause(); + + /** + * Returns the value of the 'redirect in same state' flow execution attribute if set or otherwise it falls back on + * the value returned by {@link #getRedirectOnPause()}. + * @return true or false + */ + boolean getRedirectInSameState(); + + /** + * Returns true if the flow current flow execution was launched in embedded page mode. When a flow is embedded on a + * page it can make different assumptions with regards to whether redirect after post is necessary. + */ + boolean getEmbeddedMode(); + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/State.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/State.java index f4e11c55..c8352808 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/State.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/State.java @@ -1,240 +1,240 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.webflow.core.AnnotatedObject; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.StateDefinition; -import org.springframework.webflow.execution.FlowExecutionException; - -/** - * A point in a flow where something happens. What happens is determined by a state's type. Standard types of states - * include action states, view states, subflow states, and end states. - *

- * Each state is associated with exactly one owning flow definition. Specializations of this class capture all the - * configuration information needed for a specific kind of state. - *

- * Subclasses should implement the doEnter method to execute the processing that should occur when this - * state is entered, acting on its configuration information. The ability to plug-in custom state types that execute - * different behaviors is the classic GoF state pattern. - *

- * Equality: Two states are equal if they have the same id and are part of the same flow. - * - * @see org.springframework.webflow.engine.TransitionableState - * @see org.springframework.webflow.engine.ActionState - * @see org.springframework.webflow.engine.ViewState - * @see org.springframework.webflow.engine.SubflowState - * @see org.springframework.webflow.engine.EndState - * @see org.springframework.webflow.engine.DecisionState - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public abstract class State extends AnnotatedObject implements StateDefinition { - - /** - * Logger, for use in subclasses. - */ - protected final Log logger = LogFactory.getLog(getClass()); - - /** - * The state's owning flow. - */ - private Flow flow; - - /** - * The state identifier, unique to the owning flow. - */ - private String id; - - /** - * The list of actions to invoke when this state is entered. - */ - private ActionList entryActionList = new ActionList(); - - /** - * The set of exception handlers for this state. - */ - private FlowExecutionExceptionHandlerSet exceptionHandlerSet = new FlowExecutionExceptionHandlerSet(); - - /** - * Creates a state for the provided flow identified by the provided id. The id must be - * locally unique to the owning flow. The state will be automatically added to the flow. - * @param flow the owning flow - * @param id the state identifier (must be unique to the flow) - * @throws IllegalArgumentException if this state cannot be added to the flow, for instance when the provided id is - * not unique in the owning flow - * @see #getEntryActionList() - * @see #getExceptionHandlerSet() - */ - protected State(Flow flow, String id) throws IllegalArgumentException { - setId(id); - setFlow(flow); - } - - // implementing StateDefinition - - public FlowDefinition getOwner() { - return flow; - } - - public String getId() { - return id; - } - - public boolean isViewState() { - return false; - } - - // implementation specific - - /** - * Returns the owning flow. - */ - public Flow getFlow() { - return flow; - } - - /** - * Set the owning flow. - * @throws IllegalArgumentException if this state cannot be added to the flow - */ - private void setFlow(Flow flow) throws IllegalArgumentException { - Assert.hasText(getId(), "The id of the state should be set before adding the state to a flow"); - Assert.notNull(flow, "The owning flow is required"); - this.flow = flow; - flow.add(this); - } - - /** - * Set the state identifier, unique to the owning flow. - * @param id the state identifier - */ - private void setId(String id) { - Assert.hasText(id, "This state must have a valid identifier"); - this.id = id; - } - - /** - * Returns the list of actions executed by this state when it is entered. The returned list is mutable. - * @return the state entry action list - */ - public ActionList getEntryActionList() { - return entryActionList; - } - - /** - * Returns a mutable set of exception handlers, allowing manipulation of how exceptions are handled when thrown - * within this state. - *

- * Exception handlers are invoked when an exception occurs when this state is entered, and can execute custom - * exception handling logic as well as select an error view to display. - * @return the state exception handler set - */ - public FlowExecutionExceptionHandlerSet getExceptionHandlerSet() { - return exceptionHandlerSet; - } - - /** - * Returns a flag indicating if this state is the start state of its owning flow. - * @return true if the flow is the start state, false otherwise - */ - public boolean isStartState() { - return flow.getStartState() == this; - } - - // id and flow based equality - - public boolean equals(Object o) { - if (!(o instanceof State)) { - return false; - } - State other = (State) o; - return id.equals(other.id) && flow.equals(other.flow); - } - - public int hashCode() { - return id.hashCode() + flow.hashCode(); - } - - // behavioral methods - - /** - * Enter this state in the provided flow control context. This implementation just calls the - * {@link #doEnter(RequestControlContext)} hook method, which should be implemented by subclasses, after executing - * the entry actions. - * @param context the control context for the currently executing flow, used by this state to manipulate the flow - * execution - * @throws FlowExecutionException if an exception occurs in this state - */ - public final void enter(RequestControlContext context) throws FlowExecutionException { - if (logger.isDebugEnabled()) { - logger.debug("Entering state '" + getId() + "' of flow '" + getFlow().getId() + "'"); - } - context.setCurrentState(this); - doPreEntryActions(context); - entryActionList.execute(context); - doEnter(context); - } - - /** - * Hook method to execute before running state entry actions upon state entry. Does nothing by default. Subclasses - * may override. - * @param context the request control context - * @throws FlowExecutionException if an exception occurs - */ - protected void doPreEntryActions(RequestControlContext context) throws FlowExecutionException { - - } - - /** - * Hook method to execute custom behavior as a result of entering this state. By implementing this method subclasses - * specialize the behavior of the state. - * @param context the control context for the currently executing flow, used by this state to manipulate the flow - * execution - * @throws FlowExecutionException if an exception occurs in this state - */ - protected abstract void doEnter(RequestControlContext context) throws FlowExecutionException; - - /** - * Handle an exception that occurred in this state during the context of the current flow execution request. - * @param exception the exception that occurred - * @param context the flow execution control context - */ - public boolean handleException(FlowExecutionException exception, RequestControlContext context) { - return getExceptionHandlerSet().handleException(exception, context); - } - - public String toString() { - ToStringCreator creator = new ToStringCreator(this).append("id", getId()).append("flow", flow.getId()) - .append("entryActionList", entryActionList).append("exceptionHandlerSet", exceptionHandlerSet); - appendToString(creator); - return creator.toString(); - } - - /** - * Subclasses may override this hook method to print their internal state to a string. This default implementation - * does nothing. - * @param creator the toString creator, to print properties to string - * @see #toString() - */ - protected void appendToString(ToStringCreator creator) { - } +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.webflow.core.AnnotatedObject; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.StateDefinition; +import org.springframework.webflow.execution.FlowExecutionException; + +/** + * A point in a flow where something happens. What happens is determined by a state's type. Standard types of states + * include action states, view states, subflow states, and end states. + *

+ * Each state is associated with exactly one owning flow definition. Specializations of this class capture all the + * configuration information needed for a specific kind of state. + *

+ * Subclasses should implement the doEnter method to execute the processing that should occur when this + * state is entered, acting on its configuration information. The ability to plug-in custom state types that execute + * different behaviors is the classic GoF state pattern. + *

+ * Equality: Two states are equal if they have the same id and are part of the same flow. + * + * @see org.springframework.webflow.engine.TransitionableState + * @see org.springframework.webflow.engine.ActionState + * @see org.springframework.webflow.engine.ViewState + * @see org.springframework.webflow.engine.SubflowState + * @see org.springframework.webflow.engine.EndState + * @see org.springframework.webflow.engine.DecisionState + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public abstract class State extends AnnotatedObject implements StateDefinition { + + /** + * Logger, for use in subclasses. + */ + protected final Log logger = LogFactory.getLog(getClass()); + + /** + * The state's owning flow. + */ + private Flow flow; + + /** + * The state identifier, unique to the owning flow. + */ + private String id; + + /** + * The list of actions to invoke when this state is entered. + */ + private ActionList entryActionList = new ActionList(); + + /** + * The set of exception handlers for this state. + */ + private FlowExecutionExceptionHandlerSet exceptionHandlerSet = new FlowExecutionExceptionHandlerSet(); + + /** + * Creates a state for the provided flow identified by the provided id. The id must be + * locally unique to the owning flow. The state will be automatically added to the flow. + * @param flow the owning flow + * @param id the state identifier (must be unique to the flow) + * @throws IllegalArgumentException if this state cannot be added to the flow, for instance when the provided id is + * not unique in the owning flow + * @see #getEntryActionList() + * @see #getExceptionHandlerSet() + */ + protected State(Flow flow, String id) throws IllegalArgumentException { + setId(id); + setFlow(flow); + } + + // implementing StateDefinition + + public FlowDefinition getOwner() { + return flow; + } + + public String getId() { + return id; + } + + public boolean isViewState() { + return false; + } + + // implementation specific + + /** + * Returns the owning flow. + */ + public Flow getFlow() { + return flow; + } + + /** + * Set the owning flow. + * @throws IllegalArgumentException if this state cannot be added to the flow + */ + private void setFlow(Flow flow) throws IllegalArgumentException { + Assert.hasText(getId(), "The id of the state should be set before adding the state to a flow"); + Assert.notNull(flow, "The owning flow is required"); + this.flow = flow; + flow.add(this); + } + + /** + * Set the state identifier, unique to the owning flow. + * @param id the state identifier + */ + private void setId(String id) { + Assert.hasText(id, "This state must have a valid identifier"); + this.id = id; + } + + /** + * Returns the list of actions executed by this state when it is entered. The returned list is mutable. + * @return the state entry action list + */ + public ActionList getEntryActionList() { + return entryActionList; + } + + /** + * Returns a mutable set of exception handlers, allowing manipulation of how exceptions are handled when thrown + * within this state. + *

+ * Exception handlers are invoked when an exception occurs when this state is entered, and can execute custom + * exception handling logic as well as select an error view to display. + * @return the state exception handler set + */ + public FlowExecutionExceptionHandlerSet getExceptionHandlerSet() { + return exceptionHandlerSet; + } + + /** + * Returns a flag indicating if this state is the start state of its owning flow. + * @return true if the flow is the start state, false otherwise + */ + public boolean isStartState() { + return flow.getStartState() == this; + } + + // id and flow based equality + + public boolean equals(Object o) { + if (!(o instanceof State)) { + return false; + } + State other = (State) o; + return id.equals(other.id) && flow.equals(other.flow); + } + + public int hashCode() { + return id.hashCode() + flow.hashCode(); + } + + // behavioral methods + + /** + * Enter this state in the provided flow control context. This implementation just calls the + * {@link #doEnter(RequestControlContext)} hook method, which should be implemented by subclasses, after executing + * the entry actions. + * @param context the control context for the currently executing flow, used by this state to manipulate the flow + * execution + * @throws FlowExecutionException if an exception occurs in this state + */ + public final void enter(RequestControlContext context) throws FlowExecutionException { + if (logger.isDebugEnabled()) { + logger.debug("Entering state '" + getId() + "' of flow '" + getFlow().getId() + "'"); + } + context.setCurrentState(this); + doPreEntryActions(context); + entryActionList.execute(context); + doEnter(context); + } + + /** + * Hook method to execute before running state entry actions upon state entry. Does nothing by default. Subclasses + * may override. + * @param context the request control context + * @throws FlowExecutionException if an exception occurs + */ + protected void doPreEntryActions(RequestControlContext context) throws FlowExecutionException { + + } + + /** + * Hook method to execute custom behavior as a result of entering this state. By implementing this method subclasses + * specialize the behavior of the state. + * @param context the control context for the currently executing flow, used by this state to manipulate the flow + * execution + * @throws FlowExecutionException if an exception occurs in this state + */ + protected abstract void doEnter(RequestControlContext context) throws FlowExecutionException; + + /** + * Handle an exception that occurred in this state during the context of the current flow execution request. + * @param exception the exception that occurred + * @param context the flow execution control context + */ + public boolean handleException(FlowExecutionException exception, RequestControlContext context) { + return getExceptionHandlerSet().handleException(exception, context); + } + + public String toString() { + ToStringCreator creator = new ToStringCreator(this).append("id", getId()).append("flow", flow.getId()) + .append("entryActionList", entryActionList).append("exceptionHandlerSet", exceptionHandlerSet); + appendToString(creator); + return creator.toString(); + } + + /** + * Subclasses may override this hook method to print their internal state to a string. This default implementation + * does nothing. + * @param creator the toString creator, to print properties to string + * @see #toString() + */ + protected void appendToString(ToStringCreator creator) { + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/SubflowState.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/SubflowState.java index e3a2eb9a..8b5d57fb 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/SubflowState.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/SubflowState.java @@ -1,124 +1,124 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import org.springframework.binding.expression.Expression; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.core.collection.LocalAttributeMap; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.execution.FlowExecutionException; - -/** - * A transitionable state that spawns a subflow when executed. When the subflow this state spawns ends, the ending - * result is used as grounds for a state transition out of this state. - *

- * A subflow state may be configured to map input data from its flow -- acting as the parent flow -- down to the subflow - * when the subflow is spawned. In addition, output data produced by the subflow may be mapped up to the parent flow - * when the subflow ends and the parent flow resumes. See the {@link SubflowAttributeMapper} interface definition for - * more information on how to do this. The logic for ending a subflow is located in the {@link EndState} implementation. - * - * @see org.springframework.webflow.engine.SubflowAttributeMapper - * @see org.springframework.webflow.engine.EndState - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class SubflowState extends TransitionableState { - - /** - * The subflow that should be spawned when this subflow state is entered. - */ - private Expression subflow; - - /** - * The attribute mapper that should map attributes from the parent flow down to the spawned subflow and visa versa. - */ - private SubflowAttributeMapper subflowAttributeMapper; - - /** - * Create a new subflow state. - * @param flow the owning flow - * @param id the state identifier (must be unique to the flow) - * @param subflow the subflow to spawn - * @throws IllegalArgumentException when this state cannot be added to given flow, e.g. because the id is not unique - * @see #setAttributeMapper(SubflowAttributeMapper) - */ - public SubflowState(Flow flow, String id, Expression subflow) throws IllegalArgumentException { - super(flow, id); - setSubflow(subflow); - } - - /** - * Set the subflow this state will call. - */ - private void setSubflow(Expression subflow) { - Assert.notNull(subflow, "A subflow state must have a subflow; the subflow is required"); - this.subflow = subflow; - } - - /** - * Set the attribute mapper used to map model data between the parent and child flow. - */ - public void setAttributeMapper(SubflowAttributeMapper attributeMapper) { - this.subflowAttributeMapper = attributeMapper; - } - - /** - * Specialization of State's doEnter template method that executes behaviour specific to this state - * type in polymorphic fashion. - *

- * Entering this state, creates the subflow input map and spawns the subflow in the current flow execution. - * @param context the control context for the currently executing flow, used by this state to manipulate the flow - * execution - * @throws FlowExecutionException if an exception occurs in this state - */ - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - MutableAttributeMap flowInput; - if (subflowAttributeMapper != null) { - flowInput = subflowAttributeMapper.createSubflowInput(context); - } else { - flowInput = new LocalAttributeMap<>(); - } - Flow subflow = (Flow) this.subflow.getValue(context); - if (logger.isDebugEnabled()) { - logger.debug("Calling subflow '" + subflow.getId() + "' with input " + flowInput); - } - context.start(subflow, flowInput); - } - - /** - * Called on completion of the subflow to handle the subflow result event as determined by the end state reached by - * the subflow. - */ - public boolean handleEvent(RequestControlContext context) { - if (subflowAttributeMapper != null) { - AttributeMap subflowOutput = context.getCurrentEvent().getAttributes(); - if (logger.isDebugEnabled()) { - logger.debug("Mapping subflow output " + subflowOutput); - } - subflowAttributeMapper.mapSubflowOutput(subflowOutput, context); - } - return super.handleEvent(context); - } - - protected void appendToString(ToStringCreator creator) { - creator.append("subflow", subflow).append("subflowAttributeMapper", subflowAttributeMapper); - super.appendToString(creator); - } - -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import org.springframework.binding.expression.Expression; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.core.collection.LocalAttributeMap; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.execution.FlowExecutionException; + +/** + * A transitionable state that spawns a subflow when executed. When the subflow this state spawns ends, the ending + * result is used as grounds for a state transition out of this state. + *

+ * A subflow state may be configured to map input data from its flow -- acting as the parent flow -- down to the subflow + * when the subflow is spawned. In addition, output data produced by the subflow may be mapped up to the parent flow + * when the subflow ends and the parent flow resumes. See the {@link SubflowAttributeMapper} interface definition for + * more information on how to do this. The logic for ending a subflow is located in the {@link EndState} implementation. + * + * @see org.springframework.webflow.engine.SubflowAttributeMapper + * @see org.springframework.webflow.engine.EndState + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class SubflowState extends TransitionableState { + + /** + * The subflow that should be spawned when this subflow state is entered. + */ + private Expression subflow; + + /** + * The attribute mapper that should map attributes from the parent flow down to the spawned subflow and visa versa. + */ + private SubflowAttributeMapper subflowAttributeMapper; + + /** + * Create a new subflow state. + * @param flow the owning flow + * @param id the state identifier (must be unique to the flow) + * @param subflow the subflow to spawn + * @throws IllegalArgumentException when this state cannot be added to given flow, e.g. because the id is not unique + * @see #setAttributeMapper(SubflowAttributeMapper) + */ + public SubflowState(Flow flow, String id, Expression subflow) throws IllegalArgumentException { + super(flow, id); + setSubflow(subflow); + } + + /** + * Set the subflow this state will call. + */ + private void setSubflow(Expression subflow) { + Assert.notNull(subflow, "A subflow state must have a subflow; the subflow is required"); + this.subflow = subflow; + } + + /** + * Set the attribute mapper used to map model data between the parent and child flow. + */ + public void setAttributeMapper(SubflowAttributeMapper attributeMapper) { + this.subflowAttributeMapper = attributeMapper; + } + + /** + * Specialization of State's doEnter template method that executes behaviour specific to this state + * type in polymorphic fashion. + *

+ * Entering this state, creates the subflow input map and spawns the subflow in the current flow execution. + * @param context the control context for the currently executing flow, used by this state to manipulate the flow + * execution + * @throws FlowExecutionException if an exception occurs in this state + */ + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + MutableAttributeMap flowInput; + if (subflowAttributeMapper != null) { + flowInput = subflowAttributeMapper.createSubflowInput(context); + } else { + flowInput = new LocalAttributeMap<>(); + } + Flow subflow = (Flow) this.subflow.getValue(context); + if (logger.isDebugEnabled()) { + logger.debug("Calling subflow '" + subflow.getId() + "' with input " + flowInput); + } + context.start(subflow, flowInput); + } + + /** + * Called on completion of the subflow to handle the subflow result event as determined by the end state reached by + * the subflow. + */ + public boolean handleEvent(RequestControlContext context) { + if (subflowAttributeMapper != null) { + AttributeMap subflowOutput = context.getCurrentEvent().getAttributes(); + if (logger.isDebugEnabled()) { + logger.debug("Mapping subflow output " + subflowOutput); + } + subflowAttributeMapper.mapSubflowOutput(subflowOutput, context); + } + return super.handleEvent(context); + } + + protected void appendToString(ToStringCreator creator) { + creator.append("subflow", subflow).append("subflowAttributeMapper", subflowAttributeMapper); + super.appendToString(creator); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/TargetStateResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/TargetStateResolver.java index 7ef42874..df5c63b5 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/TargetStateResolver.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/TargetStateResolver.java @@ -1,37 +1,37 @@ -/* - * 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 - * - * https://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.engine; - -import org.springframework.webflow.execution.RequestContext; - -/** - * A strategy for calculating the target state of a transition. This facilitates dynamic transition target state - * resolution that takes into account runtime contextual information. - * - * @author Keith Donald - */ -public interface TargetStateResolver { - - /** - * Resolve the target state of the transition from the source state in the current request context. Should never - * return null. - * @param transition the transition - * @param sourceState the source state of the transition, could be null - * @param context the current request context - * @return the transition's target state - may be null if no state change should occur - */ - State resolveTargetState(Transition transition, State sourceState, RequestContext context); +/* + * 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 + * + * https://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.engine; + +import org.springframework.webflow.execution.RequestContext; + +/** + * A strategy for calculating the target state of a transition. This facilitates dynamic transition target state + * resolution that takes into account runtime contextual information. + * + * @author Keith Donald + */ +public interface TargetStateResolver { + + /** + * Resolve the target state of the transition from the source state in the current request context. Should never + * return null. + * @param transition the transition + * @param sourceState the source state of the transition, could be null + * @param context the current request context + * @return the transition's target state - may be null if no state change should occur + */ + State resolveTargetState(Transition transition, State sourceState, RequestContext context); } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/Transition.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/Transition.java index caa60fc4..45ce9cd1 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/Transition.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/Transition.java @@ -1,249 +1,249 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.webflow.core.AnnotatedObject; -import org.springframework.webflow.definition.TransitionDefinition; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.execution.RequestContext; - -/** - * A path from one {@link TransitionableState state} to another {@link State state}. - *

- * When executed a transition takes a flow execution from its current state, called the source state, to another - * state, called the target state. A transition may become eligible for execution on the occurrence of an - * {@link Event} from within a transitionable source state. - *

- * When an event occurs within this transition's source TransitionableState the determination of the - * eligibility of this transition is made by a TransitionCriteria object called the matching - * criteria. If the matching criteria returns true this transition is marked eligible for execution for - * that event. - *

- * Determination as to whether an eligible transition should be allowed to execute is made by a - * TransitionCriteria object called the execution criteria. If the execution criteria test fails - * this transition will roll back and reenter its source state. If the execution criteria test succeeds this - * transition will execute and take the flow to the transition's target state. - *

- * The target state of this transition is typically specified at configuration time in a static manner. If the target - * state of this transition needs to be calculated in a dynamic fashion at runtime configure a - * {@link TargetStateResolver} that supports such calculations. - * - * @see TransitionableState - * @see TransitionCriteria - * @see TargetStateResolver - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class Transition extends AnnotatedObject implements TransitionDefinition { - - /** - * Logger, for use in subclasses. - */ - protected final Log logger = LogFactory.getLog(Transition.class); - - /** - * The criteria that determine whether or not this transition matches as eligible for execution when an event occurs - * in the source state. - */ - private TransitionCriteria matchingCriteria; - - /** - * The criteria that determine whether or not this transition, once matched, should complete execution or should - * roll back. - */ - private TransitionCriteria executionCriteria = WildcardTransitionCriteria.INSTANCE; - - /** - * The resolver responsible for calculating the target state of this transition. - */ - private TargetStateResolver targetStateResolver; - - /** - * Create a new transition that always matches and always executes, but its execution does nothing by default. - * @see #setMatchingCriteria(TransitionCriteria) - * @see #setExecutionCriteria(TransitionCriteria) - * @see #setTargetStateResolver(TargetStateResolver) - */ - public Transition() { - this(WildcardTransitionCriteria.INSTANCE, null); - } - - /** - * Create a new transition that always matches and always executes, transitioning to the target state calculated by - * the provided targetStateResolver. - * @param targetStateResolver the resolver of the target state of this transition - * @see #setMatchingCriteria(TransitionCriteria) - * @see #setExecutionCriteria(TransitionCriteria) - */ - public Transition(TargetStateResolver targetStateResolver) { - this(WildcardTransitionCriteria.INSTANCE, targetStateResolver); - } - - /** - * Create a new transition that matches on the specified criteria, transitioning to the target state calculated by - * the provided targetStateResolver. - * @param matchingCriteria the criteria for matching this transition - * @param targetStateResolver the resolver of the target state of this transition - * @see #setExecutionCriteria(TransitionCriteria) - */ - public Transition(TransitionCriteria matchingCriteria, TargetStateResolver targetStateResolver) { - setMatchingCriteria(matchingCriteria); - setTargetStateResolver(targetStateResolver); - } - - // implementing transition definition - - public String getId() { - return matchingCriteria.toString(); - } - - public String getTargetStateId() { - if (targetStateResolver != null) { - return targetStateResolver.toString(); - } else { - return null; - } - } - - /** - * Returns the criteria that determine whether or not this transition matches as eligible for execution. - * @return the transition matching criteria - */ - public TransitionCriteria getMatchingCriteria() { - return matchingCriteria; - } - - /** - * Set the criteria that determine whether or not this transition matches as eligible for execution. - * @param matchingCriteria the transition matching criteria - */ - public void setMatchingCriteria(TransitionCriteria matchingCriteria) { - Assert.notNull(matchingCriteria, "The criteria for matching this transition is required"); - this.matchingCriteria = matchingCriteria; - } - - /** - * Returns the criteria that determine whether or not this transition, once matched, should complete execution or - * should roll back. - * @return the transition execution criteria - */ - public TransitionCriteria getExecutionCriteria() { - return executionCriteria; - } - - /** - * Set the criteria that determine whether or not this transition, once matched, should complete execution or should - * roll back. - * @param executionCriteria the transition execution criteria - */ - public void setExecutionCriteria(TransitionCriteria executionCriteria) { - this.executionCriteria = executionCriteria; - } - - /** - * Returns this transition's target state resolver. - */ - public TargetStateResolver getTargetStateResolver() { - return targetStateResolver; - } - - /** - * Set this transition's target state resolver, to calculate what state to transition to when this transition is - * executed. - * @param targetStateResolver the target state resolver - */ - public void setTargetStateResolver(TargetStateResolver targetStateResolver) { - this.targetStateResolver = targetStateResolver; - } - - /** - * Checks if this transition is eligible for execution given the state of the provided flow execution request - * context. - * @param context the flow execution request context - * @return true if this transition should execute, false otherwise - */ - public boolean matches(RequestContext context) { - return matchingCriteria.test(context); - } - - /** - * Checks if this transition can complete its execution or should be rolled back, given the state of the flow - * execution request context. - * @param context the flow execution request context - * @return true if this transition can complete execution, false if it should roll back - */ - public boolean canExecute(RequestContext context) { - if (executionCriteria != null) { - return executionCriteria.test(context); - } else { - return false; - } - } - - /** - * Execute this state transition. Should only be called if the {@link #matches(RequestContext)} method returns true - * for the given context. - * @param sourceState the source state to transition from, may be null if the current state is null - * @param context the flow execution control context - * @return a boolean indicating if executing this transition caused the current state to exit and a new state to - * enter - * @throws FlowExecutionException when transition execution fails - */ - public boolean execute(State sourceState, RequestControlContext context) throws FlowExecutionException { - if (canExecute(context)) { - if (logger.isDebugEnabled()) { - logger.debug("Executing " + this); - } - context.setCurrentTransition(this); - if (targetStateResolver != null) { - State targetState = targetStateResolver.resolveTargetState(this, sourceState, context); - if (targetState != null) { - if (sourceState != null) { - if (logger.isDebugEnabled()) { - logger.debug("Exiting state '" + sourceState.getId() + "'"); - } - if (sourceState instanceof TransitionableState) { - ((TransitionableState) sourceState).exit(context); - } - } - targetState.enter(context); - if (logger.isDebugEnabled()) { - if (context.getFlowExecutionContext().isActive()) { - logger.debug("Completed transition execution. As a result, the new state is '" - + context.getCurrentState().getId() + "' in flow '" - + context.getActiveFlow().getId() + "'"); - } else { - logger.debug("Completed transition execution. As a result, the flow execution has ended"); - } - } - return true; - } - } - } - return false; - } - - public String toString() { - return new ToStringCreator(this).append("on", getMatchingCriteria()).append("to", getTargetStateResolver()) - .toString(); - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.webflow.core.AnnotatedObject; +import org.springframework.webflow.definition.TransitionDefinition; +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.execution.RequestContext; + +/** + * A path from one {@link TransitionableState state} to another {@link State state}. + *

+ * When executed a transition takes a flow execution from its current state, called the source state, to another + * state, called the target state. A transition may become eligible for execution on the occurrence of an + * {@link Event} from within a transitionable source state. + *

+ * When an event occurs within this transition's source TransitionableState the determination of the + * eligibility of this transition is made by a TransitionCriteria object called the matching + * criteria. If the matching criteria returns true this transition is marked eligible for execution for + * that event. + *

+ * Determination as to whether an eligible transition should be allowed to execute is made by a + * TransitionCriteria object called the execution criteria. If the execution criteria test fails + * this transition will roll back and reenter its source state. If the execution criteria test succeeds this + * transition will execute and take the flow to the transition's target state. + *

+ * The target state of this transition is typically specified at configuration time in a static manner. If the target + * state of this transition needs to be calculated in a dynamic fashion at runtime configure a + * {@link TargetStateResolver} that supports such calculations. + * + * @see TransitionableState + * @see TransitionCriteria + * @see TargetStateResolver + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class Transition extends AnnotatedObject implements TransitionDefinition { + + /** + * Logger, for use in subclasses. + */ + protected final Log logger = LogFactory.getLog(Transition.class); + + /** + * The criteria that determine whether or not this transition matches as eligible for execution when an event occurs + * in the source state. + */ + private TransitionCriteria matchingCriteria; + + /** + * The criteria that determine whether or not this transition, once matched, should complete execution or should + * roll back. + */ + private TransitionCriteria executionCriteria = WildcardTransitionCriteria.INSTANCE; + + /** + * The resolver responsible for calculating the target state of this transition. + */ + private TargetStateResolver targetStateResolver; + + /** + * Create a new transition that always matches and always executes, but its execution does nothing by default. + * @see #setMatchingCriteria(TransitionCriteria) + * @see #setExecutionCriteria(TransitionCriteria) + * @see #setTargetStateResolver(TargetStateResolver) + */ + public Transition() { + this(WildcardTransitionCriteria.INSTANCE, null); + } + + /** + * Create a new transition that always matches and always executes, transitioning to the target state calculated by + * the provided targetStateResolver. + * @param targetStateResolver the resolver of the target state of this transition + * @see #setMatchingCriteria(TransitionCriteria) + * @see #setExecutionCriteria(TransitionCriteria) + */ + public Transition(TargetStateResolver targetStateResolver) { + this(WildcardTransitionCriteria.INSTANCE, targetStateResolver); + } + + /** + * Create a new transition that matches on the specified criteria, transitioning to the target state calculated by + * the provided targetStateResolver. + * @param matchingCriteria the criteria for matching this transition + * @param targetStateResolver the resolver of the target state of this transition + * @see #setExecutionCriteria(TransitionCriteria) + */ + public Transition(TransitionCriteria matchingCriteria, TargetStateResolver targetStateResolver) { + setMatchingCriteria(matchingCriteria); + setTargetStateResolver(targetStateResolver); + } + + // implementing transition definition + + public String getId() { + return matchingCriteria.toString(); + } + + public String getTargetStateId() { + if (targetStateResolver != null) { + return targetStateResolver.toString(); + } else { + return null; + } + } + + /** + * Returns the criteria that determine whether or not this transition matches as eligible for execution. + * @return the transition matching criteria + */ + public TransitionCriteria getMatchingCriteria() { + return matchingCriteria; + } + + /** + * Set the criteria that determine whether or not this transition matches as eligible for execution. + * @param matchingCriteria the transition matching criteria + */ + public void setMatchingCriteria(TransitionCriteria matchingCriteria) { + Assert.notNull(matchingCriteria, "The criteria for matching this transition is required"); + this.matchingCriteria = matchingCriteria; + } + + /** + * Returns the criteria that determine whether or not this transition, once matched, should complete execution or + * should roll back. + * @return the transition execution criteria + */ + public TransitionCriteria getExecutionCriteria() { + return executionCriteria; + } + + /** + * Set the criteria that determine whether or not this transition, once matched, should complete execution or should + * roll back. + * @param executionCriteria the transition execution criteria + */ + public void setExecutionCriteria(TransitionCriteria executionCriteria) { + this.executionCriteria = executionCriteria; + } + + /** + * Returns this transition's target state resolver. + */ + public TargetStateResolver getTargetStateResolver() { + return targetStateResolver; + } + + /** + * Set this transition's target state resolver, to calculate what state to transition to when this transition is + * executed. + * @param targetStateResolver the target state resolver + */ + public void setTargetStateResolver(TargetStateResolver targetStateResolver) { + this.targetStateResolver = targetStateResolver; + } + + /** + * Checks if this transition is eligible for execution given the state of the provided flow execution request + * context. + * @param context the flow execution request context + * @return true if this transition should execute, false otherwise + */ + public boolean matches(RequestContext context) { + return matchingCriteria.test(context); + } + + /** + * Checks if this transition can complete its execution or should be rolled back, given the state of the flow + * execution request context. + * @param context the flow execution request context + * @return true if this transition can complete execution, false if it should roll back + */ + public boolean canExecute(RequestContext context) { + if (executionCriteria != null) { + return executionCriteria.test(context); + } else { + return false; + } + } + + /** + * Execute this state transition. Should only be called if the {@link #matches(RequestContext)} method returns true + * for the given context. + * @param sourceState the source state to transition from, may be null if the current state is null + * @param context the flow execution control context + * @return a boolean indicating if executing this transition caused the current state to exit and a new state to + * enter + * @throws FlowExecutionException when transition execution fails + */ + public boolean execute(State sourceState, RequestControlContext context) throws FlowExecutionException { + if (canExecute(context)) { + if (logger.isDebugEnabled()) { + logger.debug("Executing " + this); + } + context.setCurrentTransition(this); + if (targetStateResolver != null) { + State targetState = targetStateResolver.resolveTargetState(this, sourceState, context); + if (targetState != null) { + if (sourceState != null) { + if (logger.isDebugEnabled()) { + logger.debug("Exiting state '" + sourceState.getId() + "'"); + } + if (sourceState instanceof TransitionableState) { + ((TransitionableState) sourceState).exit(context); + } + } + targetState.enter(context); + if (logger.isDebugEnabled()) { + if (context.getFlowExecutionContext().isActive()) { + logger.debug("Completed transition execution. As a result, the new state is '" + + context.getCurrentState().getId() + "' in flow '" + + context.getActiveFlow().getId() + "'"); + } else { + logger.debug("Completed transition execution. As a result, the flow execution has ended"); + } + } + return true; + } + } + } + return false; + } + + public String toString() { + return new ToStringCreator(this).append("on", getMatchingCriteria()).append("to", getTargetStateResolver()) + .toString(); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionCriteria.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionCriteria.java index 397bf0dd..cf2f6aa1 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionCriteria.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionCriteria.java @@ -1,39 +1,39 @@ -/* - * 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 - * - * https://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.engine; - -import org.springframework.webflow.execution.RequestContext; - -/** - * Strategy interface encapsulating criteria that determine whether or not a transition should execute given a flow - * execution request context. - * - * @see org.springframework.webflow.engine.Transition - * @see org.springframework.webflow.execution.RequestContext - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface TransitionCriteria { - - /** - * Check if the transition should fire based on the given flow execution request context. - * @param context the flow execution request context - * @return true if the transition should fire, false otherwise - */ - boolean test(RequestContext context); - +/* + * 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 + * + * https://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.engine; + +import org.springframework.webflow.execution.RequestContext; + +/** + * Strategy interface encapsulating criteria that determine whether or not a transition should execute given a flow + * execution request context. + * + * @see org.springframework.webflow.engine.Transition + * @see org.springframework.webflow.execution.RequestContext + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface TransitionCriteria { + + /** + * Check if the transition should fire based on the given flow execution request context. + * @param context the flow execution request context + * @return true if the transition should fire, false otherwise + */ + boolean test(RequestContext context); + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionSet.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionSet.java index 890e4786..d3b2ee71 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionSet.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionSet.java @@ -1,142 +1,142 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.core.style.StylerUtils; -import org.springframework.webflow.core.collection.CollectionUtils; -import org.springframework.webflow.execution.RequestContext; - -/** - * A typed set of transitions for use internally by artifacts that can apply transition execution logic. - * - * @see TransitionableState#getTransitionSet() - * @see Flow#getGlobalTransitionSet() - * - * @author Keith Donald - */ -public class TransitionSet implements Iterable { - - /** - * The set of transitions. - */ - private List transitions = new LinkedList<>(); - - /** - * Add a transition to this set. - * @param transition the transition to add - * @return true if this set's contents changed as a result of the add operation - */ - public boolean add(Transition transition) { - if (contains(transition)) { - return false; - } - return transitions.add(transition); - } - - /** - * Add a collection of transition instances to this set. - * @param transitions the transitions to add - * @return true if this set's contents changed as a result of the add operation - */ - public boolean addAll(Transition... transitions) { - return CollectionUtils.addAllNoDuplicates(this.transitions, transitions); - } - - /** - * Tests if this transition is in this set. - * @param transition the transition - * @return true if the transition is contained in this set, false otherwise - */ - public boolean contains(Transition transition) { - return transitions.contains(transition); - } - - /** - * Remove the transition instance from this set. - * @param transition the transition to remove - * @return true if this list's contents changed as a result of the remove operation - */ - public boolean remove(Transition transition) { - return transitions.remove(transition); - } - - /** - * Returns the size of this transition set. - * @return the exception handler set size - */ - public int size() { - return transitions.size(); - } - - /** - * Returns an iterator over this transition set. - * @return an iterator - */ - public Iterator iterator() { - return transitions.iterator(); - } - - /** - * Convert this set to a typed transition array. - * @return the transition set as a typed array - */ - public Transition[] toArray() { - return transitions.toArray(new Transition[transitions.size()]); - } - - /** - * Returns a list of the supported transitional criteria used to match transitions in this state. - * @return the list of transitional criteria - */ - public TransitionCriteria[] getTransitionCriterias() { - TransitionCriteria[] criterias = new TransitionCriteria[transitions.size()]; - int i = 0; - for (Transition transition : transitions) { - criterias[i++] = transition.getMatchingCriteria(); - } - return criterias; - } - - /** - * Gets a transition for given flow execution request context. The first matching transition will be returned. - * @param context a flow execution context - * @return the transition, or null if no transition matches - */ - public Transition getTransition(RequestContext context) { - for (Transition transition : transitions) { - if (transition.matches(context)) { - return transition; - } - } - return null; - } - - /** - * Returns whether or not this list has a transition that will fire for given flow execution request context. - * @param context a flow execution context - */ - public boolean hasMatchingTransition(RequestContext context) { - return getTransition(context) != null; - } - - public String toString() { - return StylerUtils.style(transitions); - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.springframework.core.style.StylerUtils; +import org.springframework.webflow.core.collection.CollectionUtils; +import org.springframework.webflow.execution.RequestContext; + +/** + * A typed set of transitions for use internally by artifacts that can apply transition execution logic. + * + * @see TransitionableState#getTransitionSet() + * @see Flow#getGlobalTransitionSet() + * + * @author Keith Donald + */ +public class TransitionSet implements Iterable { + + /** + * The set of transitions. + */ + private List transitions = new LinkedList<>(); + + /** + * Add a transition to this set. + * @param transition the transition to add + * @return true if this set's contents changed as a result of the add operation + */ + public boolean add(Transition transition) { + if (contains(transition)) { + return false; + } + return transitions.add(transition); + } + + /** + * Add a collection of transition instances to this set. + * @param transitions the transitions to add + * @return true if this set's contents changed as a result of the add operation + */ + public boolean addAll(Transition... transitions) { + return CollectionUtils.addAllNoDuplicates(this.transitions, transitions); + } + + /** + * Tests if this transition is in this set. + * @param transition the transition + * @return true if the transition is contained in this set, false otherwise + */ + public boolean contains(Transition transition) { + return transitions.contains(transition); + } + + /** + * Remove the transition instance from this set. + * @param transition the transition to remove + * @return true if this list's contents changed as a result of the remove operation + */ + public boolean remove(Transition transition) { + return transitions.remove(transition); + } + + /** + * Returns the size of this transition set. + * @return the exception handler set size + */ + public int size() { + return transitions.size(); + } + + /** + * Returns an iterator over this transition set. + * @return an iterator + */ + public Iterator iterator() { + return transitions.iterator(); + } + + /** + * Convert this set to a typed transition array. + * @return the transition set as a typed array + */ + public Transition[] toArray() { + return transitions.toArray(new Transition[transitions.size()]); + } + + /** + * Returns a list of the supported transitional criteria used to match transitions in this state. + * @return the list of transitional criteria + */ + public TransitionCriteria[] getTransitionCriterias() { + TransitionCriteria[] criterias = new TransitionCriteria[transitions.size()]; + int i = 0; + for (Transition transition : transitions) { + criterias[i++] = transition.getMatchingCriteria(); + } + return criterias; + } + + /** + * Gets a transition for given flow execution request context. The first matching transition will be returned. + * @param context a flow execution context + * @return the transition, or null if no transition matches + */ + public Transition getTransition(RequestContext context) { + for (Transition transition : transitions) { + if (transition.matches(context)) { + return transition; + } + } + return null; + } + + /** + * Returns whether or not this list has a transition that will fire for given flow execution request context. + * @param context a flow execution context + */ + public boolean hasMatchingTransition(RequestContext context) { + return getTransition(context) != null; + } + + public String toString() { + return StylerUtils.style(transitions); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionableState.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionableState.java index 405c2dea..9011f5a4 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionableState.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/TransitionableState.java @@ -1,131 +1,131 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import org.springframework.core.style.StylerUtils; -import org.springframework.core.style.ToStringCreator; -import org.springframework.webflow.definition.TransitionDefinition; -import org.springframework.webflow.definition.TransitionableStateDefinition; -import org.springframework.webflow.execution.RequestContext; - -/** - * Abstract superclass for states that can execute a transition in response to an event. - * - * @see org.springframework.webflow.engine.Transition - * @see org.springframework.webflow.engine.TransitionCriteria - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public abstract class TransitionableState extends State implements TransitionableStateDefinition { - - /** - * The set of possible transitions out of this state. - */ - private TransitionSet transitions = new TransitionSet(); - - /** - * An actions to execute when exiting this state. - */ - private ActionList exitActionList = new ActionList(); - - /** - * Create a new transitionable state. - * @param flow the owning flow - * @param id the state identifier (must be unique to the flow) - * @throws IllegalArgumentException when this state cannot be added to given flow, for instance when the id is not - * unique - * @see State#State(Flow, String) - * @see #getTransitionSet() - */ - protected TransitionableState(Flow flow, String id) throws IllegalArgumentException { - super(flow, id); - } - - // implementing TranstionableStateDefinition - - public TransitionDefinition[] getTransitions() { - return getTransitionSet().toArray(); - } - - public TransitionDefinition getTransition(String eventId) { - for (Transition transition : transitions) { - if (transition.getId().equals(eventId)) { - return transition; - } - } - return null; - } - - // impl - - /** - * Returns the set of transitions. The returned set is mutable. - */ - public TransitionSet getTransitionSet() { - return transitions; - } - - /** - * Get a transition in this state for given flow execution request context. Throws and exception when there is no - * corresponding transition. - * @throws NoMatchingTransitionException when a matching transition cannot be found - */ - public Transition getRequiredTransition(RequestContext context) throws NoMatchingTransitionException { - Transition transition = getTransitionSet().getTransition(context); - if (transition == null) { - throw new NoMatchingTransitionException(getFlow().getId(), getId(), context.getCurrentEvent(), - "No transition found on occurence of event '" + context.getCurrentEvent() + "' in state '" - + getId() + "' of flow '" + getFlow().getId() + "' -- valid transitional criteria are " - + StylerUtils.style(getTransitionSet().getTransitionCriterias()) - + " -- likely programmer error, check the set of TransitionCriteria for this state"); - } - return transition; - } - - /** - * Returns the list of actions executed by this state when it is exited. The returned list is mutable. - * @return the state exit action list - */ - public ActionList getExitActionList() { - return exitActionList; - } - - // behavioral methods - - /** - * Inform this state definition that an event was signaled in it. The signaled event is the last event available in - * given request context ({@link RequestContext#getCurrentEvent()}). - * @param context the flow execution control context - * @throws NoMatchingTransitionException when a matching transition cannot be found - */ - public boolean handleEvent(RequestControlContext context) throws NoMatchingTransitionException { - return context.execute(getRequiredTransition(context)); - } - - /** - * Exit this state. This is typically called when a transition takes the flow out of this state into another state. - * By default just executes any registered exit actions. - * @param context the flow control context - */ - public void exit(RequestControlContext context) { - exitActionList.execute(context); - } - - protected void appendToString(ToStringCreator creator) { - creator.append("transitions", transitions).append("exitActionList", exitActionList); - } +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import org.springframework.core.style.StylerUtils; +import org.springframework.core.style.ToStringCreator; +import org.springframework.webflow.definition.TransitionDefinition; +import org.springframework.webflow.definition.TransitionableStateDefinition; +import org.springframework.webflow.execution.RequestContext; + +/** + * Abstract superclass for states that can execute a transition in response to an event. + * + * @see org.springframework.webflow.engine.Transition + * @see org.springframework.webflow.engine.TransitionCriteria + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public abstract class TransitionableState extends State implements TransitionableStateDefinition { + + /** + * The set of possible transitions out of this state. + */ + private TransitionSet transitions = new TransitionSet(); + + /** + * An actions to execute when exiting this state. + */ + private ActionList exitActionList = new ActionList(); + + /** + * Create a new transitionable state. + * @param flow the owning flow + * @param id the state identifier (must be unique to the flow) + * @throws IllegalArgumentException when this state cannot be added to given flow, for instance when the id is not + * unique + * @see State#State(Flow, String) + * @see #getTransitionSet() + */ + protected TransitionableState(Flow flow, String id) throws IllegalArgumentException { + super(flow, id); + } + + // implementing TranstionableStateDefinition + + public TransitionDefinition[] getTransitions() { + return getTransitionSet().toArray(); + } + + public TransitionDefinition getTransition(String eventId) { + for (Transition transition : transitions) { + if (transition.getId().equals(eventId)) { + return transition; + } + } + return null; + } + + // impl + + /** + * Returns the set of transitions. The returned set is mutable. + */ + public TransitionSet getTransitionSet() { + return transitions; + } + + /** + * Get a transition in this state for given flow execution request context. Throws and exception when there is no + * corresponding transition. + * @throws NoMatchingTransitionException when a matching transition cannot be found + */ + public Transition getRequiredTransition(RequestContext context) throws NoMatchingTransitionException { + Transition transition = getTransitionSet().getTransition(context); + if (transition == null) { + throw new NoMatchingTransitionException(getFlow().getId(), getId(), context.getCurrentEvent(), + "No transition found on occurence of event '" + context.getCurrentEvent() + "' in state '" + + getId() + "' of flow '" + getFlow().getId() + "' -- valid transitional criteria are " + + StylerUtils.style(getTransitionSet().getTransitionCriterias()) + + " -- likely programmer error, check the set of TransitionCriteria for this state"); + } + return transition; + } + + /** + * Returns the list of actions executed by this state when it is exited. The returned list is mutable. + * @return the state exit action list + */ + public ActionList getExitActionList() { + return exitActionList; + } + + // behavioral methods + + /** + * Inform this state definition that an event was signaled in it. The signaled event is the last event available in + * given request context ({@link RequestContext#getCurrentEvent()}). + * @param context the flow execution control context + * @throws NoMatchingTransitionException when a matching transition cannot be found + */ + public boolean handleEvent(RequestControlContext context) throws NoMatchingTransitionException { + return context.execute(getRequiredTransition(context)); + } + + /** + * Exit this state. This is typically called when a transition takes the flow out of this state into another state. + * By default just executes any registered exit actions. + * @param context the flow control context + */ + public void exit(RequestControlContext context) { + exitActionList.execute(context); + } + + protected void appendToString(ToStringCreator creator) { + creator.append("transitions", transitions).append("exitActionList", exitActionList); + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/WildcardTransitionCriteria.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/WildcardTransitionCriteria.java index 29dcdc9c..79c138a5 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/WildcardTransitionCriteria.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/WildcardTransitionCriteria.java @@ -1,63 +1,63 @@ -/* - * 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 - * - * https://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.engine; - -import java.io.ObjectStreamException; -import java.io.Serializable; - -import org.springframework.webflow.execution.RequestContext; - -/** - * Transition criteria that always returns true. - * - * @author Keith Donald - */ -public class WildcardTransitionCriteria implements TransitionCriteria, Serializable { - - /* - * Implementation note: not located in webflow.execution.support package to avoid a cyclic dependency between - * webflow.execution and webflow.execution.support. - */ - - /** - * Event id value ("*") that will cause the transition to match on any event. - */ - public static final String WILDCARD_EVENT_ID = "*"; - - /** - * Shared instance of a TransitionCriteria that always returns true. - */ - public static final WildcardTransitionCriteria INSTANCE = new WildcardTransitionCriteria(); - - /** - * Private constructor because this is a singleton. - */ - private WildcardTransitionCriteria() { - } - - public boolean test(RequestContext context) { - return true; - } - - // resolve the singleton instance - private Object readResolve() throws ObjectStreamException { - return INSTANCE; - } - - public String toString() { - return WILDCARD_EVENT_ID; - } +/* + * 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 + * + * https://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.engine; + +import java.io.ObjectStreamException; +import java.io.Serializable; + +import org.springframework.webflow.execution.RequestContext; + +/** + * Transition criteria that always returns true. + * + * @author Keith Donald + */ +public class WildcardTransitionCriteria implements TransitionCriteria, Serializable { + + /* + * Implementation note: not located in webflow.execution.support package to avoid a cyclic dependency between + * webflow.execution and webflow.execution.support. + */ + + /** + * Event id value ("*") that will cause the transition to match on any event. + */ + public static final String WILDCARD_EVENT_ID = "*"; + + /** + * Shared instance of a TransitionCriteria that always returns true. + */ + public static final WildcardTransitionCriteria INSTANCE = new WildcardTransitionCriteria(); + + /** + * Private constructor because this is a singleton. + */ + private WildcardTransitionCriteria() { + } + + public boolean test(RequestContext context) { + return true; + } + + // resolve the singleton instance + private Object readResolve() throws ObjectStreamException { + return INSTANCE; + } + + public String toString() { + return WILDCARD_EVENT_ID; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/DefaultFlowHolder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/DefaultFlowHolder.java index 793dcbe9..1e4cb7a7 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/DefaultFlowHolder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/DefaultFlowHolder.java @@ -1,125 +1,125 @@ -/* - * 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 - * - * https://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.engine.builder; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.registry.FlowDefinitionConstructionException; -import org.springframework.webflow.definition.registry.FlowDefinitionHolder; - -/** - * A flow definition holder that can detect changes on an underlying flow definition resource and refresh that resource - * automatically. - *

- * This class is thread-safe. - *

- * Note that this {@link FlowDefinition} holder uses a {@link FlowAssembler}. This class bridges the abstract - * world of {@link FlowDefinition flow definitions} with the concrete world of flow implementations. - * - * @see FlowAssembler - * @see FlowDefinition - * - * @author Keith Donald - */ -public class DefaultFlowHolder implements FlowDefinitionHolder { - - private static final Log logger = LogFactory.getLog(DefaultFlowHolder.class); - - /** - * The flow definition assembled by this assembler, initially null. - */ - private FlowDefinition flowDefinition; - - /** - * The flow assembler. - */ - private FlowAssembler assembler; - - /** - * A flag indicating whether or not this holder is in the middle of the assembly process. - */ - private boolean assembling; - - /** - * Creates a new refreshable flow definition holder that uses the configured assembler (GOF director) to drive flow - * assembly, on initial use and on any resource change or refresh. - * @param assembler the flow assembler to use - */ - public DefaultFlowHolder(FlowAssembler assembler) { - Assert.notNull(assembler, "The FlowAssembler is required"); - this.assembler = assembler; - } - - public String getFlowDefinitionId() { - return assembler.getFlowBuilderContext().getFlowId(); - } - - public String getFlowDefinitionResourceString() { - return assembler.getFlowBuilder().getFlowResourceString(); - } - - public synchronized FlowDefinition getFlowDefinition() throws FlowDefinitionConstructionException { - if (assembling) { - // must return early assembly result for when a flow calls itself recursively - return getFlowBuilder().getFlow(); - } - if (flowDefinition == null) { - logger.debug("Assembling the flow for the first time"); - assembleFlow(); - } else { - if (flowDefinition.inDevelopment() && getFlowBuilder().hasFlowChanged()) { - logger.debug("The flow under development has changed; reassembling..."); - assembleFlow(); - } - } - return flowDefinition; - } - - public synchronized void refresh() throws FlowDefinitionConstructionException { - assembleFlow(); - } - - public void destroy() { - if (flowDefinition != null) { - flowDefinition.destroy(); - } - } - - // internal helpers - - private void assembleFlow() throws FlowDefinitionConstructionException { - try { - assembling = true; - flowDefinition = assembler.assembleFlow(); - } catch (FlowBuilderException e) { - throw new FlowDefinitionConstructionException(assembler.getFlowBuilderContext().getFlowId(), e); - } finally { - assembling = false; - } - } - - private FlowBuilder getFlowBuilder() { - return assembler.getFlowBuilder(); - } - - public String toString() { - return new ToStringCreator(this).append("flowBuilder", assembler.getFlowBuilder()).toString(); - } - +/* + * 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 + * + * https://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.engine.builder; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.registry.FlowDefinitionConstructionException; +import org.springframework.webflow.definition.registry.FlowDefinitionHolder; + +/** + * A flow definition holder that can detect changes on an underlying flow definition resource and refresh that resource + * automatically. + *

+ * This class is thread-safe. + *

+ * Note that this {@link FlowDefinition} holder uses a {@link FlowAssembler}. This class bridges the abstract + * world of {@link FlowDefinition flow definitions} with the concrete world of flow implementations. + * + * @see FlowAssembler + * @see FlowDefinition + * + * @author Keith Donald + */ +public class DefaultFlowHolder implements FlowDefinitionHolder { + + private static final Log logger = LogFactory.getLog(DefaultFlowHolder.class); + + /** + * The flow definition assembled by this assembler, initially null. + */ + private FlowDefinition flowDefinition; + + /** + * The flow assembler. + */ + private FlowAssembler assembler; + + /** + * A flag indicating whether or not this holder is in the middle of the assembly process. + */ + private boolean assembling; + + /** + * Creates a new refreshable flow definition holder that uses the configured assembler (GOF director) to drive flow + * assembly, on initial use and on any resource change or refresh. + * @param assembler the flow assembler to use + */ + public DefaultFlowHolder(FlowAssembler assembler) { + Assert.notNull(assembler, "The FlowAssembler is required"); + this.assembler = assembler; + } + + public String getFlowDefinitionId() { + return assembler.getFlowBuilderContext().getFlowId(); + } + + public String getFlowDefinitionResourceString() { + return assembler.getFlowBuilder().getFlowResourceString(); + } + + public synchronized FlowDefinition getFlowDefinition() throws FlowDefinitionConstructionException { + if (assembling) { + // must return early assembly result for when a flow calls itself recursively + return getFlowBuilder().getFlow(); + } + if (flowDefinition == null) { + logger.debug("Assembling the flow for the first time"); + assembleFlow(); + } else { + if (flowDefinition.inDevelopment() && getFlowBuilder().hasFlowChanged()) { + logger.debug("The flow under development has changed; reassembling..."); + assembleFlow(); + } + } + return flowDefinition; + } + + public synchronized void refresh() throws FlowDefinitionConstructionException { + assembleFlow(); + } + + public void destroy() { + if (flowDefinition != null) { + flowDefinition.destroy(); + } + } + + // internal helpers + + private void assembleFlow() throws FlowDefinitionConstructionException { + try { + assembling = true; + flowDefinition = assembler.assembleFlow(); + } catch (FlowBuilderException e) { + throw new FlowDefinitionConstructionException(assembler.getFlowBuilderContext().getFlowId(), e); + } finally { + assembling = false; + } + } + + private FlowBuilder getFlowBuilder() { + return assembler.getFlowBuilder(); + } + + public String toString() { + return new ToStringCreator(this).append("flowBuilder", assembler.getFlowBuilder()).toString(); + } + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java index 6e80d2d8..7d23bee6 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowArtifactFactory.java @@ -1,239 +1,239 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.builder; - -import org.springframework.binding.expression.Expression; -import org.springframework.binding.mapping.Mapper; -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.engine.ActionState; -import org.springframework.webflow.engine.DecisionState; -import org.springframework.webflow.engine.EndState; -import org.springframework.webflow.engine.Flow; -import org.springframework.webflow.engine.FlowExecutionExceptionHandler; -import org.springframework.webflow.engine.State; -import org.springframework.webflow.engine.SubflowAttributeMapper; -import org.springframework.webflow.engine.SubflowState; -import org.springframework.webflow.engine.TargetStateResolver; -import org.springframework.webflow.engine.Transition; -import org.springframework.webflow.engine.TransitionCriteria; -import org.springframework.webflow.engine.TransitionableState; -import org.springframework.webflow.engine.ViewState; -import org.springframework.webflow.engine.ViewVariable; -import org.springframework.webflow.execution.Action; -import org.springframework.webflow.execution.ViewFactory; - -/** - * A factory for core web flow elements such as {@link Flow flows}, {@link State states}, and {@link Transition - * transitions}. - *

- * This factory encapsulates the construction of each Flow implementation as well as each core artifact type. Subclasses - * may customize how the core elements are created. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class FlowArtifactFactory { - - /** - * Factory method that creates a new {@link Flow} definition object. - *

- * Note this method does not return a fully configured Flow instance, it only encapsulates the selection of - * implementation. A {@link FlowAssembler} delegating to a calling {@link FlowBuilder} is expected to assemble the - * Flow fully before returning it to external clients. - * @param id the flow identifier, should be unique to all flows in an application (required) - * @param attributes attributes to assign to the Flow, which may also be used to affect flow construction; may be - * null - * @return the initial flow instance, ready for assembly by a FlowBuilder - */ - public Flow createFlow(String id, AttributeMap attributes) { - return Flow.create(id, attributes); - } - - /** - * Factory method that creates a new view state, a state where a user is allowed to participate in the flow. This - * method is an atomic operation that returns a fully initialized state. It encapsulates the selection of the view - * state implementation as well as the state assembly. - * @param id the identifier to assign to the state, must be unique to its owning flow (required) - * @param flow the flow that will own (contain) this state (required) - * @param entryActions any state entry actions; may be null - * @param viewFactory the state view factory strategy - * @param redirect whether to send a flow execution redirect before rendering - * @param popup whether to display the view in a popup window - * @param renderActions any 'render actions' to execute on entry and refresh; may be null - * @param transitions any transitions (paths) out of this state; may be null - * @param exceptionHandlers any exception handlers; may be null - * @param exitActions any state exit actions; may be null - * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be - * null - * @return the fully initialized view state instance - */ - public State createViewState(String id, Flow flow, ViewVariable[] variables, Action[] entryActions, - ViewFactory viewFactory, Boolean redirect, boolean popup, Action[] renderActions, Transition[] transitions, - FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap attributes) { - ViewState viewState = new ViewState(flow, id, viewFactory); - viewState.addVariables(variables); - viewState.setRedirect(redirect); - viewState.setPopup(popup); - viewState.getRenderActionList().addAll(renderActions); - configureCommonProperties(viewState, entryActions, transitions, exceptionHandlers, exitActions, attributes); - return viewState; - } - - /** - * Factory method that creates a new action state, a state where a system action is executed. This method is an - * atomic operation that returns a fully initialized state. It encapsulates the selection of the action state - * implementation as well as the state assembly. - * @param id the identifier to assign to the state, must be unique to its owning flow (required) - * @param flow the flow that will own (contain) this state (required) - * @param entryActions any state entry actions; may be null - * @param actions the actions to execute when the state is entered (required) - * @param transitions any transitions (paths) out of this state; may be null - * @param exceptionHandlers any exception handlers; may be null - * @param exitActions any state exit actions; may be null - * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be - * null - * @return the fully initialized action state instance - */ - public State createActionState(String id, Flow flow, Action[] entryActions, Action[] actions, - Transition[] transitions, FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, - AttributeMap attributes) { - ActionState actionState = new ActionState(flow, id); - actionState.getActionList().addAll(actions); - configureCommonProperties(actionState, entryActions, transitions, exceptionHandlers, exitActions, attributes); - return actionState; - } - - /** - * Factory method that creates a new decision state, a state where a flow routing decision is made. This method is - * an atomic operation that returns a fully initialized state. It encapsulates the selection of the decision state - * implementation as well as the state assembly. - * @param id the identifier to assign to the state, must be unique to its owning flow (required) - * @param flow the flow that will own (contain) this state (required) - * @param entryActions any state entry actions; may be null - * @param transitions any transitions (paths) out of this state - * @param exceptionHandlers any exception handlers; may be null - * @param exitActions any state exit actions; may be null - * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be - * null - * @return the fully initialized decision state instance - */ - public State createDecisionState(String id, Flow flow, Action[] entryActions, Transition[] transitions, - FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap attributes) { - DecisionState decisionState = new DecisionState(flow, id); - configureCommonProperties(decisionState, entryActions, transitions, exceptionHandlers, exitActions, attributes); - return decisionState; - } - - /** - * Factory method that creates a new subflow state, a state where a parent flow spawns another flow as a subflow. - * This method is an atomic operation that returns a fully initialized state. It encapsulates the selection of the - * subflow state implementation as well as the state assembly. - * @param id the identifier to assign to the state, must be unique to its owning flow (required) - * @param flow the flow that will own (contain) this state (required) - * @param entryActions any state entry actions; may be null - * @param subflow the subflow definition (required) - * @param attributeMapper the subflow input and output attribute mapper; may be null - * @param transitions any transitions (paths) out of this state - * @param exceptionHandlers any exception handlers; may be null - * @param exitActions any state exit actions; may be null - * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be - * null - * @return the fully initialized subflow state instance - */ - public State createSubflowState(String id, Flow flow, Action[] entryActions, Expression subflow, - SubflowAttributeMapper attributeMapper, Transition[] transitions, - FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap attributes) { - SubflowState subflowState = new SubflowState(flow, id, subflow); - if (attributeMapper != null) { - subflowState.setAttributeMapper(attributeMapper); - } - configureCommonProperties(subflowState, entryActions, transitions, exceptionHandlers, exitActions, attributes); - return subflowState; - } - - /** - * Factory method that creates a new end state, a state where an executing flow session terminates. This method is - * an atomic operation that returns a fully initialized state. It encapsulates the selection of the end state - * implementation as well as the state assembly. - * @param id the identifier to assign to the state, must be unique to its owning flow (required) - * @param flow the flow that will own (contain) this state (required) - * @param entryActions any state entry actions; may be null - * @param finalResponseAction the state response renderer; may be null - * @param outputMapper the state output mapper; may be null - * @param exceptionHandlers any exception handlers; may be null - * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be - * null - * @return the fully initialized subflow state instance - */ - public State createEndState(String id, Flow flow, Action[] entryActions, Action finalResponseAction, - Mapper outputMapper, FlowExecutionExceptionHandler[] exceptionHandlers, AttributeMap attributes) { - EndState endState = new EndState(flow, id); - if (finalResponseAction != null) { - endState.setFinalResponseAction(finalResponseAction); - } - if (outputMapper != null) { - endState.setOutputMapper(outputMapper); - } - configureCommonProperties(endState, entryActions, exceptionHandlers, attributes); - return endState; - } - - /** - * Factory method that creates a new transition, a path from one step in a flow to another. This method is an atomic - * operation that returns a fully initialized transition. It encapsulates the selection of the transition - * implementation as well as the transition assembly. - * @param targetStateResolver the resolver of the target state of the transition (required) - * @param matchingCriteria the criteria that matches the transition; may be null - * @param executionCriteria the criteria that governs execution of the transition after match; may be null - * @param attributes attributes to assign to the transition, which may also be used to affect transition - * construction; may be null - * @return the fully initialized transition instance - */ - public Transition createTransition(TargetStateResolver targetStateResolver, TransitionCriteria matchingCriteria, - TransitionCriteria executionCriteria, AttributeMap attributes) { - Transition transition = new Transition(targetStateResolver); - if (matchingCriteria != null) { - transition.setMatchingCriteria(matchingCriteria); - } - if (executionCriteria != null) { - transition.setExecutionCriteria(executionCriteria); - } - transition.getAttributes().putAll(attributes); - return transition; - } - - // internal helpers - - /** - * Configure common properties for a transitionable state. - */ - private void configureCommonProperties(TransitionableState state, Action[] entryActions, Transition[] transitions, - FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap attributes) { - configureCommonProperties(state, entryActions, exceptionHandlers, attributes); - state.getTransitionSet().addAll(transitions); - state.getExitActionList().addAll(exitActions); - } - - /** - * Configure common properties for a state. - */ - private void configureCommonProperties(State state, Action[] entryActions, - FlowExecutionExceptionHandler[] exceptionHandlers, AttributeMap attributes) { - state.getEntryActionList().addAll(entryActions); - state.getExceptionHandlerSet().addAll(exceptionHandlers); - state.getAttributes().putAll(attributes); - } +/* + * Copyright 2004-2012 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 + * + * https://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.engine.builder; + +import org.springframework.binding.expression.Expression; +import org.springframework.binding.mapping.Mapper; +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.engine.ActionState; +import org.springframework.webflow.engine.DecisionState; +import org.springframework.webflow.engine.EndState; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.engine.FlowExecutionExceptionHandler; +import org.springframework.webflow.engine.State; +import org.springframework.webflow.engine.SubflowAttributeMapper; +import org.springframework.webflow.engine.SubflowState; +import org.springframework.webflow.engine.TargetStateResolver; +import org.springframework.webflow.engine.Transition; +import org.springframework.webflow.engine.TransitionCriteria; +import org.springframework.webflow.engine.TransitionableState; +import org.springframework.webflow.engine.ViewState; +import org.springframework.webflow.engine.ViewVariable; +import org.springframework.webflow.execution.Action; +import org.springframework.webflow.execution.ViewFactory; + +/** + * A factory for core web flow elements such as {@link Flow flows}, {@link State states}, and {@link Transition + * transitions}. + *

+ * This factory encapsulates the construction of each Flow implementation as well as each core artifact type. Subclasses + * may customize how the core elements are created. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class FlowArtifactFactory { + + /** + * Factory method that creates a new {@link Flow} definition object. + *

+ * Note this method does not return a fully configured Flow instance, it only encapsulates the selection of + * implementation. A {@link FlowAssembler} delegating to a calling {@link FlowBuilder} is expected to assemble the + * Flow fully before returning it to external clients. + * @param id the flow identifier, should be unique to all flows in an application (required) + * @param attributes attributes to assign to the Flow, which may also be used to affect flow construction; may be + * null + * @return the initial flow instance, ready for assembly by a FlowBuilder + */ + public Flow createFlow(String id, AttributeMap attributes) { + return Flow.create(id, attributes); + } + + /** + * Factory method that creates a new view state, a state where a user is allowed to participate in the flow. This + * method is an atomic operation that returns a fully initialized state. It encapsulates the selection of the view + * state implementation as well as the state assembly. + * @param id the identifier to assign to the state, must be unique to its owning flow (required) + * @param flow the flow that will own (contain) this state (required) + * @param entryActions any state entry actions; may be null + * @param viewFactory the state view factory strategy + * @param redirect whether to send a flow execution redirect before rendering + * @param popup whether to display the view in a popup window + * @param renderActions any 'render actions' to execute on entry and refresh; may be null + * @param transitions any transitions (paths) out of this state; may be null + * @param exceptionHandlers any exception handlers; may be null + * @param exitActions any state exit actions; may be null + * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be + * null + * @return the fully initialized view state instance + */ + public State createViewState(String id, Flow flow, ViewVariable[] variables, Action[] entryActions, + ViewFactory viewFactory, Boolean redirect, boolean popup, Action[] renderActions, Transition[] transitions, + FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap attributes) { + ViewState viewState = new ViewState(flow, id, viewFactory); + viewState.addVariables(variables); + viewState.setRedirect(redirect); + viewState.setPopup(popup); + viewState.getRenderActionList().addAll(renderActions); + configureCommonProperties(viewState, entryActions, transitions, exceptionHandlers, exitActions, attributes); + return viewState; + } + + /** + * Factory method that creates a new action state, a state where a system action is executed. This method is an + * atomic operation that returns a fully initialized state. It encapsulates the selection of the action state + * implementation as well as the state assembly. + * @param id the identifier to assign to the state, must be unique to its owning flow (required) + * @param flow the flow that will own (contain) this state (required) + * @param entryActions any state entry actions; may be null + * @param actions the actions to execute when the state is entered (required) + * @param transitions any transitions (paths) out of this state; may be null + * @param exceptionHandlers any exception handlers; may be null + * @param exitActions any state exit actions; may be null + * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be + * null + * @return the fully initialized action state instance + */ + public State createActionState(String id, Flow flow, Action[] entryActions, Action[] actions, + Transition[] transitions, FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, + AttributeMap attributes) { + ActionState actionState = new ActionState(flow, id); + actionState.getActionList().addAll(actions); + configureCommonProperties(actionState, entryActions, transitions, exceptionHandlers, exitActions, attributes); + return actionState; + } + + /** + * Factory method that creates a new decision state, a state where a flow routing decision is made. This method is + * an atomic operation that returns a fully initialized state. It encapsulates the selection of the decision state + * implementation as well as the state assembly. + * @param id the identifier to assign to the state, must be unique to its owning flow (required) + * @param flow the flow that will own (contain) this state (required) + * @param entryActions any state entry actions; may be null + * @param transitions any transitions (paths) out of this state + * @param exceptionHandlers any exception handlers; may be null + * @param exitActions any state exit actions; may be null + * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be + * null + * @return the fully initialized decision state instance + */ + public State createDecisionState(String id, Flow flow, Action[] entryActions, Transition[] transitions, + FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap attributes) { + DecisionState decisionState = new DecisionState(flow, id); + configureCommonProperties(decisionState, entryActions, transitions, exceptionHandlers, exitActions, attributes); + return decisionState; + } + + /** + * Factory method that creates a new subflow state, a state where a parent flow spawns another flow as a subflow. + * This method is an atomic operation that returns a fully initialized state. It encapsulates the selection of the + * subflow state implementation as well as the state assembly. + * @param id the identifier to assign to the state, must be unique to its owning flow (required) + * @param flow the flow that will own (contain) this state (required) + * @param entryActions any state entry actions; may be null + * @param subflow the subflow definition (required) + * @param attributeMapper the subflow input and output attribute mapper; may be null + * @param transitions any transitions (paths) out of this state + * @param exceptionHandlers any exception handlers; may be null + * @param exitActions any state exit actions; may be null + * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be + * null + * @return the fully initialized subflow state instance + */ + public State createSubflowState(String id, Flow flow, Action[] entryActions, Expression subflow, + SubflowAttributeMapper attributeMapper, Transition[] transitions, + FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap attributes) { + SubflowState subflowState = new SubflowState(flow, id, subflow); + if (attributeMapper != null) { + subflowState.setAttributeMapper(attributeMapper); + } + configureCommonProperties(subflowState, entryActions, transitions, exceptionHandlers, exitActions, attributes); + return subflowState; + } + + /** + * Factory method that creates a new end state, a state where an executing flow session terminates. This method is + * an atomic operation that returns a fully initialized state. It encapsulates the selection of the end state + * implementation as well as the state assembly. + * @param id the identifier to assign to the state, must be unique to its owning flow (required) + * @param flow the flow that will own (contain) this state (required) + * @param entryActions any state entry actions; may be null + * @param finalResponseAction the state response renderer; may be null + * @param outputMapper the state output mapper; may be null + * @param exceptionHandlers any exception handlers; may be null + * @param attributes attributes to assign to the State, which may also be used to affect state construction; may be + * null + * @return the fully initialized subflow state instance + */ + public State createEndState(String id, Flow flow, Action[] entryActions, Action finalResponseAction, + Mapper outputMapper, FlowExecutionExceptionHandler[] exceptionHandlers, AttributeMap attributes) { + EndState endState = new EndState(flow, id); + if (finalResponseAction != null) { + endState.setFinalResponseAction(finalResponseAction); + } + if (outputMapper != null) { + endState.setOutputMapper(outputMapper); + } + configureCommonProperties(endState, entryActions, exceptionHandlers, attributes); + return endState; + } + + /** + * Factory method that creates a new transition, a path from one step in a flow to another. This method is an atomic + * operation that returns a fully initialized transition. It encapsulates the selection of the transition + * implementation as well as the transition assembly. + * @param targetStateResolver the resolver of the target state of the transition (required) + * @param matchingCriteria the criteria that matches the transition; may be null + * @param executionCriteria the criteria that governs execution of the transition after match; may be null + * @param attributes attributes to assign to the transition, which may also be used to affect transition + * construction; may be null + * @return the fully initialized transition instance + */ + public Transition createTransition(TargetStateResolver targetStateResolver, TransitionCriteria matchingCriteria, + TransitionCriteria executionCriteria, AttributeMap attributes) { + Transition transition = new Transition(targetStateResolver); + if (matchingCriteria != null) { + transition.setMatchingCriteria(matchingCriteria); + } + if (executionCriteria != null) { + transition.setExecutionCriteria(executionCriteria); + } + transition.getAttributes().putAll(attributes); + return transition; + } + + // internal helpers + + /** + * Configure common properties for a transitionable state. + */ + private void configureCommonProperties(TransitionableState state, Action[] entryActions, Transition[] transitions, + FlowExecutionExceptionHandler[] exceptionHandlers, Action[] exitActions, AttributeMap attributes) { + configureCommonProperties(state, entryActions, exceptionHandlers, attributes); + state.getTransitionSet().addAll(transitions); + state.getExitActionList().addAll(exitActions); + } + + /** + * Configure common properties for a state. + */ + private void configureCommonProperties(State state, Action[] entryActions, + FlowExecutionExceptionHandler[] exceptionHandlers, AttributeMap attributes) { + state.getEntryActionList().addAll(entryActions); + state.getExceptionHandlerSet().addAll(exceptionHandlers); + state.getAttributes().putAll(attributes); + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowAssembler.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowAssembler.java index aae6f6e1..12517cb1 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowAssembler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowAssembler.java @@ -1,112 +1,112 @@ -/* - * 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 - * - * https://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.engine.builder; - -import org.springframework.util.Assert; -import org.springframework.webflow.engine.Flow; - -/** - * A director for assembling flows, delegating to a {@link FlowBuilder} to construct a flow. This class encapsulates the - * algorithm for using a FlowBuilder to assemble a Flow properly. It acts as the director in the classic GoF builder - * pattern. - *

- * Flow assemblers may be used in a standalone, programmatic fashion as follows: - * - *

- *     FlowBuilder builder = ...;
- *     FlowBuilder context = ...;
- *     Flow flow = new FlowAssembler(builder, builderContext).assembleFlow();
- * 
- * - * @see org.springframework.webflow.engine.builder.FlowBuilder - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class FlowAssembler { - - /** - * The flow builder strategy used to construct the flow from its component parts. - */ - private FlowBuilder flowBuilder; - - /** - * Context needed to initialize the builder so it can perform a build operation. - */ - private FlowBuilderContext flowBuilderContext; - - /** - * Create a new flow assembler that will direct Flow assembly using the specified builder strategy. - * @param flowBuilder the builder the factory will use to build flows - * @param flowBuilderContext context to influence the build process - */ - public FlowAssembler(FlowBuilder flowBuilder, FlowBuilderContext flowBuilderContext) { - Assert.notNull(flowBuilder, "A flow builder is required for flow assembly"); - Assert.notNull(flowBuilderContext, "A flow builder context is required for flow assembly"); - this.flowBuilder = flowBuilder; - this.flowBuilderContext = flowBuilderContext; - } - - /** - * Returns the flow builder strategy used to construct the flow from its component parts. - */ - public FlowBuilder getFlowBuilder() { - return flowBuilder; - } - - /** - * Returns the flow builder context. - * @return flow builder context - */ - public FlowBuilderContext getFlowBuilderContext() { - return flowBuilderContext; - } - - /** - * Assembles the flow, directing the construction process by delegating to the configured FlowBuilder. Every call to - * this method will assemble the Flow instance. - *

- * This will drive the flow construction process as described in the {@link FlowBuilder} JavaDoc, starting with - * builder initialization using {@link FlowBuilder#init(FlowBuilderContext)} and finishing by cleaning up the - * builder with a call to {@link FlowBuilder#dispose()}. - * @return the constructed flow - * @throws FlowBuilderException when flow assembly fails - */ - public Flow assembleFlow() throws FlowBuilderException { - try { - flowBuilder.init(flowBuilderContext); - directAssembly(); - return flowBuilder.getFlow(); - } finally { - flowBuilder.dispose(); - } - } - - /** - * Build all parts of the flow by directing flow assembly by the flow builder. - * @throws FlowBuilderException when flow assembly fails - */ - protected void directAssembly() throws FlowBuilderException { - flowBuilder.buildVariables(); - flowBuilder.buildInputMapper(); - flowBuilder.buildStartActions(); - flowBuilder.buildStates(); - flowBuilder.buildGlobalTransitions(); - flowBuilder.buildEndActions(); - flowBuilder.buildOutputMapper(); - flowBuilder.buildExceptionHandlers(); - } +/* + * 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 + * + * https://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.engine.builder; + +import org.springframework.util.Assert; +import org.springframework.webflow.engine.Flow; + +/** + * A director for assembling flows, delegating to a {@link FlowBuilder} to construct a flow. This class encapsulates the + * algorithm for using a FlowBuilder to assemble a Flow properly. It acts as the director in the classic GoF builder + * pattern. + *

+ * Flow assemblers may be used in a standalone, programmatic fashion as follows: + * + *

+ *     FlowBuilder builder = ...;
+ *     FlowBuilder context = ...;
+ *     Flow flow = new FlowAssembler(builder, builderContext).assembleFlow();
+ * 
+ * + * @see org.springframework.webflow.engine.builder.FlowBuilder + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class FlowAssembler { + + /** + * The flow builder strategy used to construct the flow from its component parts. + */ + private FlowBuilder flowBuilder; + + /** + * Context needed to initialize the builder so it can perform a build operation. + */ + private FlowBuilderContext flowBuilderContext; + + /** + * Create a new flow assembler that will direct Flow assembly using the specified builder strategy. + * @param flowBuilder the builder the factory will use to build flows + * @param flowBuilderContext context to influence the build process + */ + public FlowAssembler(FlowBuilder flowBuilder, FlowBuilderContext flowBuilderContext) { + Assert.notNull(flowBuilder, "A flow builder is required for flow assembly"); + Assert.notNull(flowBuilderContext, "A flow builder context is required for flow assembly"); + this.flowBuilder = flowBuilder; + this.flowBuilderContext = flowBuilderContext; + } + + /** + * Returns the flow builder strategy used to construct the flow from its component parts. + */ + public FlowBuilder getFlowBuilder() { + return flowBuilder; + } + + /** + * Returns the flow builder context. + * @return flow builder context + */ + public FlowBuilderContext getFlowBuilderContext() { + return flowBuilderContext; + } + + /** + * Assembles the flow, directing the construction process by delegating to the configured FlowBuilder. Every call to + * this method will assemble the Flow instance. + *

+ * This will drive the flow construction process as described in the {@link FlowBuilder} JavaDoc, starting with + * builder initialization using {@link FlowBuilder#init(FlowBuilderContext)} and finishing by cleaning up the + * builder with a call to {@link FlowBuilder#dispose()}. + * @return the constructed flow + * @throws FlowBuilderException when flow assembly fails + */ + public Flow assembleFlow() throws FlowBuilderException { + try { + flowBuilder.init(flowBuilderContext); + directAssembly(); + return flowBuilder.getFlow(); + } finally { + flowBuilder.dispose(); + } + } + + /** + * Build all parts of the flow by directing flow assembly by the flow builder. + * @throws FlowBuilderException when flow assembly fails + */ + protected void directAssembly() throws FlowBuilderException { + flowBuilder.buildVariables(); + flowBuilder.buildInputMapper(); + flowBuilder.buildStartActions(); + flowBuilder.buildStates(); + flowBuilder.buildGlobalTransitions(); + flowBuilder.buildEndActions(); + flowBuilder.buildOutputMapper(); + flowBuilder.buildExceptionHandlers(); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowBuilder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowBuilder.java index df99e05a..ed7da107 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowBuilder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowBuilder.java @@ -1,141 +1,141 @@ -/* - * 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 - * - * https://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.engine.builder; - -import org.springframework.webflow.engine.Flow; - -/** - * Builder interface used to build a flow definition. The process of building a flow consists of the following steps: - *

    - *
  1. Initialize this builder, creating the initial flow definition, by calling {@link #init(FlowBuilderContext)}. - *
  2. Call {@link #buildVariables()} to create any variables of the flow and add them to the flow definition. - *
  3. Call {@link #buildInputMapper()} to create and set the input mapper for the flow. - *
  4. Call {@link #buildStartActions()} to create and add any start actions to the flow. - *
  5. Call {@link #buildStates()} to create the states of the flow and add them to the flow definition. - *
  6. Call {@link #buildGlobalTransitions()} to create any transitions shared by all states of the flow and add them to - * the flow definition. - *
  7. Call {@link #buildEndActions()} to create and add any end actions to the flow. - *
  8. Call {@link #buildOutputMapper()} to create and set the output mapper for the flow. - *
  9. Call {@link #buildExceptionHandlers()} to create the exception handlers of the flow and add them to the flow - * definition. - *
  10. Call {@link #getFlow()} to return the fully-built {@link Flow} definition. - *
  11. Dispose this builder, releasing any resources allocated during the building process by calling {@link #dispose()}. - *
- *

- * Implementations should encapsulate flow construction logic, either for a specific kind of flow, for example, an - * OrderFlowBuilder built in Java code, or a generic flow builder strategy, like the - * XmlFlowBuilder, for building flows from an XML-definition. - *

- * Flow builders are used by the {@link FlowAssembler}, which acts as an assembler (director). Flow Builders may be - * reused, however, exercise caution when doing this as these objects are not thread safe. Also, for each use be sure to - * call init, followed by the build* methods, getFlow, and dispose completely in that order. - *

- * This is a good example of the classic GoF builder pattern. - * - * @see Flow - * @see FlowBuilderContext - * @see FlowAssembler - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface FlowBuilder { - - /** - * Initialize this builder. This could cause the builder to open a stream to an externalized resource representing - * the flow definition, for example. - * @param context the flow builder context - * @throws FlowBuilderException an exception occurred building the flow - */ - void init(FlowBuilderContext context) throws FlowBuilderException; - - /** - * Builds any variables initialized by the flow when it starts. - * @throws FlowBuilderException an exception occurred building the flow - */ - void buildVariables() throws FlowBuilderException; - - /** - * Builds the input mapper responsible for mapping flow input on start. - * @throws FlowBuilderException an exception occurred building the flow - */ - void buildInputMapper() throws FlowBuilderException; - - /** - * Builds any start actions to execute when the flow starts. - * @throws FlowBuilderException an exception occurred building the flow - */ - void buildStartActions() throws FlowBuilderException; - - /** - * Builds the states of the flow. - * @throws FlowBuilderException an exception occurred building the flow - */ - void buildStates() throws FlowBuilderException; - - /** - * Builds any transitions shared by all states of the flow. - * @throws FlowBuilderException an exception occurred building the flow - */ - void buildGlobalTransitions() throws FlowBuilderException; - - /** - * Builds any end actions to execute when the flow ends. - * @throws FlowBuilderException an exception occurred building the flow - */ - void buildEndActions() throws FlowBuilderException; - - /** - * Builds the output mapper responsible for mapping flow output on end. - * @throws FlowBuilderException an exception occurred building the flow - */ - void buildOutputMapper() throws FlowBuilderException; - - /** - * Creates and adds all exception handlers to the flow built by this builder. - * @throws FlowBuilderException an exception occurred building this flow - */ - void buildExceptionHandlers() throws FlowBuilderException; - - /** - * Get the fully constructed and configured Flow object. Called by the builder's assembler (director) after - * assembly. When this method is called by the assembler, it is expected flow construction has completed and the - * returned flow is fully configured and ready for use. - * @throws FlowBuilderException an exception occurred building this flow - */ - Flow getFlow() throws FlowBuilderException; - - /** - * Shutdown the builder, releasing any resources it holds. A new flow construction process should start with another - * call to the {@link #init(FlowBuilderContext)} method. - * @throws FlowBuilderException an exception occurred building this flow - */ - void dispose() throws FlowBuilderException; - - /** - * As the underlying flow managed by this builder changed since the last build occurred? - * @return true if changed, false if not - */ - boolean hasFlowChanged(); - - /** - * Returns a string describing the location of the flow resource; the logical location where the source code can be - * found. Used for informational purposes. - * @return the flow resource string - */ - String getFlowResourceString(); - +/* + * 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 + * + * https://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.engine.builder; + +import org.springframework.webflow.engine.Flow; + +/** + * Builder interface used to build a flow definition. The process of building a flow consists of the following steps: + *

    + *
  1. Initialize this builder, creating the initial flow definition, by calling {@link #init(FlowBuilderContext)}. + *
  2. Call {@link #buildVariables()} to create any variables of the flow and add them to the flow definition. + *
  3. Call {@link #buildInputMapper()} to create and set the input mapper for the flow. + *
  4. Call {@link #buildStartActions()} to create and add any start actions to the flow. + *
  5. Call {@link #buildStates()} to create the states of the flow and add them to the flow definition. + *
  6. Call {@link #buildGlobalTransitions()} to create any transitions shared by all states of the flow and add them to + * the flow definition. + *
  7. Call {@link #buildEndActions()} to create and add any end actions to the flow. + *
  8. Call {@link #buildOutputMapper()} to create and set the output mapper for the flow. + *
  9. Call {@link #buildExceptionHandlers()} to create the exception handlers of the flow and add them to the flow + * definition. + *
  10. Call {@link #getFlow()} to return the fully-built {@link Flow} definition. + *
  11. Dispose this builder, releasing any resources allocated during the building process by calling {@link #dispose()}. + *
+ *

+ * Implementations should encapsulate flow construction logic, either for a specific kind of flow, for example, an + * OrderFlowBuilder built in Java code, or a generic flow builder strategy, like the + * XmlFlowBuilder, for building flows from an XML-definition. + *

+ * Flow builders are used by the {@link FlowAssembler}, which acts as an assembler (director). Flow Builders may be + * reused, however, exercise caution when doing this as these objects are not thread safe. Also, for each use be sure to + * call init, followed by the build* methods, getFlow, and dispose completely in that order. + *

+ * This is a good example of the classic GoF builder pattern. + * + * @see Flow + * @see FlowBuilderContext + * @see FlowAssembler + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface FlowBuilder { + + /** + * Initialize this builder. This could cause the builder to open a stream to an externalized resource representing + * the flow definition, for example. + * @param context the flow builder context + * @throws FlowBuilderException an exception occurred building the flow + */ + void init(FlowBuilderContext context) throws FlowBuilderException; + + /** + * Builds any variables initialized by the flow when it starts. + * @throws FlowBuilderException an exception occurred building the flow + */ + void buildVariables() throws FlowBuilderException; + + /** + * Builds the input mapper responsible for mapping flow input on start. + * @throws FlowBuilderException an exception occurred building the flow + */ + void buildInputMapper() throws FlowBuilderException; + + /** + * Builds any start actions to execute when the flow starts. + * @throws FlowBuilderException an exception occurred building the flow + */ + void buildStartActions() throws FlowBuilderException; + + /** + * Builds the states of the flow. + * @throws FlowBuilderException an exception occurred building the flow + */ + void buildStates() throws FlowBuilderException; + + /** + * Builds any transitions shared by all states of the flow. + * @throws FlowBuilderException an exception occurred building the flow + */ + void buildGlobalTransitions() throws FlowBuilderException; + + /** + * Builds any end actions to execute when the flow ends. + * @throws FlowBuilderException an exception occurred building the flow + */ + void buildEndActions() throws FlowBuilderException; + + /** + * Builds the output mapper responsible for mapping flow output on end. + * @throws FlowBuilderException an exception occurred building the flow + */ + void buildOutputMapper() throws FlowBuilderException; + + /** + * Creates and adds all exception handlers to the flow built by this builder. + * @throws FlowBuilderException an exception occurred building this flow + */ + void buildExceptionHandlers() throws FlowBuilderException; + + /** + * Get the fully constructed and configured Flow object. Called by the builder's assembler (director) after + * assembly. When this method is called by the assembler, it is expected flow construction has completed and the + * returned flow is fully configured and ready for use. + * @throws FlowBuilderException an exception occurred building this flow + */ + Flow getFlow() throws FlowBuilderException; + + /** + * Shutdown the builder, releasing any resources it holds. A new flow construction process should start with another + * call to the {@link #init(FlowBuilderContext)} method. + * @throws FlowBuilderException an exception occurred building this flow + */ + void dispose() throws FlowBuilderException; + + /** + * As the underlying flow managed by this builder changed since the last build occurred? + * @return true if changed, false if not + */ + boolean hasFlowChanged(); + + /** + * Returns a string describing the location of the flow resource; the logical location where the source code can be + * found. Used for informational purposes. + * @return the flow resource string + */ + String getFlowResourceString(); + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowBuilderException.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowBuilderException.java index c6514de8..e28a639b 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowBuilderException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/FlowBuilderException.java @@ -1,45 +1,45 @@ -/* - * 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 - * - * https://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.engine.builder; - -import org.springframework.webflow.core.FlowException; - -/** - * Exception thrown to indicate a problem while building a flow. - * - * @see FlowBuilder - * - * @author Erwin Vervaet - */ -public class FlowBuilderException extends FlowException { - - /** - * Create a new flow builder exception. - * @param message descriptive message - */ - public FlowBuilderException(String message) { - super(message); - } - - /** - * Create a new flow builder exception. - * @param message descriptive message - * @param cause the underlying cause of this exception - */ - public FlowBuilderException(String message, Throwable cause) { - super(message, cause); - } +/* + * 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 + * + * https://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.engine.builder; + +import org.springframework.webflow.core.FlowException; + +/** + * Exception thrown to indicate a problem while building a flow. + * + * @see FlowBuilder + * + * @author Erwin Vervaet + */ +public class FlowBuilderException extends FlowException { + + /** + * Create a new flow builder exception. + * @param message descriptive message + */ + public FlowBuilderException(String message) { + super(message); + } + + /** + * Create a new flow builder exception. + * @param message descriptive message + * @param cause the underlying cause of this exception + */ + public FlowBuilderException(String message, Throwable cause) { + super(message, cause); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/model/LocalFlowBuilderContext.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/model/LocalFlowBuilderContext.java index c141f4ac..d7cedb56 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/model/LocalFlowBuilderContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/model/LocalFlowBuilderContext.java @@ -1,114 +1,114 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.builder.model; - -import org.springframework.binding.convert.ConversionService; -import org.springframework.binding.expression.ExpressionParser; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.GenericApplicationContext; -import org.springframework.validation.Validator; -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.definition.registry.FlowDefinitionLocator; -import org.springframework.webflow.engine.builder.FlowArtifactFactory; -import org.springframework.webflow.engine.builder.FlowBuilderContext; -import org.springframework.webflow.engine.builder.ViewFactoryCreator; -import org.springframework.webflow.validation.ValidationHintResolver; - -/** - * A builder context that delegates to a flow-local bean factory for builder services. Such builder services override - * the services of the external "parent" context. - * @author Keith Donald - */ -class LocalFlowBuilderContext implements FlowBuilderContext { - - private FlowBuilderContext parent; - - private ApplicationContext localFlowContext; - - public LocalFlowBuilderContext(FlowBuilderContext parent, GenericApplicationContext localFlowContext) { - this.parent = parent; - this.localFlowContext = localFlowContext; - } - - public ApplicationContext getApplicationContext() { - return localFlowContext; - } - - public String getFlowId() { - return parent.getFlowId(); - } - - public AttributeMap getFlowAttributes() { - return parent.getFlowAttributes(); - } - - public FlowDefinitionLocator getFlowDefinitionLocator() { - if (localFlowContext.containsLocalBean("flowRegistry")) { - return localFlowContext.getBean("flowRegistry", FlowDefinitionLocator.class); - } else { - return parent.getFlowDefinitionLocator(); - } - } - - public FlowArtifactFactory getFlowArtifactFactory() { - if (localFlowContext.containsLocalBean("flowArtifactFactory")) { - return localFlowContext.getBean("flowArtifactFactory", FlowArtifactFactory.class); - } else { - return parent.getFlowArtifactFactory(); - } - } - - public ConversionService getConversionService() { - if (localFlowContext.containsLocalBean("conversionService")) { - return localFlowContext.getBean("conversionService", ConversionService.class); - } else { - return parent.getConversionService(); - } - } - - public ViewFactoryCreator getViewFactoryCreator() { - if (localFlowContext.containsLocalBean("viewFactoryCreator")) { - return localFlowContext.getBean("viewFactoryCreator", ViewFactoryCreator.class); - } else { - return parent.getViewFactoryCreator(); - } - } - - public ExpressionParser getExpressionParser() { - if (localFlowContext.containsLocalBean("expressionParser")) { - return localFlowContext.getBean("expressionParser", ExpressionParser.class); - } else { - return parent.getExpressionParser(); - } - } - - public Validator getValidator() { - if (localFlowContext.containsLocalBean("validator")) { - return localFlowContext.getBean("validator", Validator.class); - } else { - return parent.getValidator(); - } - } - - public ValidationHintResolver getValidationHintResolver() { - if (localFlowContext.containsLocalBean("validationHintResolver")) { - return localFlowContext.getBean("validationHintResolver", ValidationHintResolver.class); - } else { - return parent.getValidationHintResolver(); - } - } - +/* + * Copyright 2004-2012 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 + * + * https://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.engine.builder.model; + +import org.springframework.binding.convert.ConversionService; +import org.springframework.binding.expression.ExpressionParser; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.validation.Validator; +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.definition.registry.FlowDefinitionLocator; +import org.springframework.webflow.engine.builder.FlowArtifactFactory; +import org.springframework.webflow.engine.builder.FlowBuilderContext; +import org.springframework.webflow.engine.builder.ViewFactoryCreator; +import org.springframework.webflow.validation.ValidationHintResolver; + +/** + * A builder context that delegates to a flow-local bean factory for builder services. Such builder services override + * the services of the external "parent" context. + * @author Keith Donald + */ +class LocalFlowBuilderContext implements FlowBuilderContext { + + private FlowBuilderContext parent; + + private ApplicationContext localFlowContext; + + public LocalFlowBuilderContext(FlowBuilderContext parent, GenericApplicationContext localFlowContext) { + this.parent = parent; + this.localFlowContext = localFlowContext; + } + + public ApplicationContext getApplicationContext() { + return localFlowContext; + } + + public String getFlowId() { + return parent.getFlowId(); + } + + public AttributeMap getFlowAttributes() { + return parent.getFlowAttributes(); + } + + public FlowDefinitionLocator getFlowDefinitionLocator() { + if (localFlowContext.containsLocalBean("flowRegistry")) { + return localFlowContext.getBean("flowRegistry", FlowDefinitionLocator.class); + } else { + return parent.getFlowDefinitionLocator(); + } + } + + public FlowArtifactFactory getFlowArtifactFactory() { + if (localFlowContext.containsLocalBean("flowArtifactFactory")) { + return localFlowContext.getBean("flowArtifactFactory", FlowArtifactFactory.class); + } else { + return parent.getFlowArtifactFactory(); + } + } + + public ConversionService getConversionService() { + if (localFlowContext.containsLocalBean("conversionService")) { + return localFlowContext.getBean("conversionService", ConversionService.class); + } else { + return parent.getConversionService(); + } + } + + public ViewFactoryCreator getViewFactoryCreator() { + if (localFlowContext.containsLocalBean("viewFactoryCreator")) { + return localFlowContext.getBean("viewFactoryCreator", ViewFactoryCreator.class); + } else { + return parent.getViewFactoryCreator(); + } + } + + public ExpressionParser getExpressionParser() { + if (localFlowContext.containsLocalBean("expressionParser")) { + return localFlowContext.getBean("expressionParser", ExpressionParser.class); + } else { + return parent.getExpressionParser(); + } + } + + public Validator getValidator() { + if (localFlowContext.containsLocalBean("validator")) { + return localFlowContext.getBean("validator", Validator.class); + } else { + return parent.getValidator(); + } + } + + public ValidationHintResolver getValidationHintResolver() { + if (localFlowContext.containsLocalBean("validationHintResolver")) { + return localFlowContext.getBean("validationHintResolver", ValidationHintResolver.class); + } else { + return parent.getValidationHintResolver(); + } + } + } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/AbstractFlowBuilder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/AbstractFlowBuilder.java index 95050654..bd997b11 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/AbstractFlowBuilder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/AbstractFlowBuilder.java @@ -1,123 +1,123 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.builder.support; - -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.engine.Flow; -import org.springframework.webflow.engine.builder.FlowBuilder; -import org.springframework.webflow.engine.builder.FlowBuilderContext; -import org.springframework.webflow.engine.builder.FlowBuilderException; - -/** - * Abstract base implementation of a flow builder defining common functionality needed by most concrete flow builder - * implementations. This class implements all optional parts of the FlowBuilder process as no-op methods. Subclasses are - * only required to implement {@link #buildStates()}. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public abstract class AbstractFlowBuilder implements FlowBuilder { - - /** - * The Flow built by this builder. - */ - private Flow flow; - - /** - * The flow builder context providing access to services needed to build the flow. - */ - private FlowBuilderContext context; - - public void init(FlowBuilderContext context) throws FlowBuilderException { - this.context = context; - doInit(); - flow = createFlow(); - } - - /** - * Flow builder initialization hook. Does nothing by default. May be overridden by subclasses. - */ - protected void doInit() { - - } - - /** - * Factory method that initially creates the flow implementation during flow builder initialization. Simply - * delegates to the configured flow artifact factory by default. - * @return the flow instance, initially created but not yet built - */ - protected Flow createFlow() { - String id = getContext().getFlowId(); - AttributeMap attributes = getContext().getFlowAttributes(); - return getContext().getFlowArtifactFactory().createFlow(id, attributes); - } - - /** - * Returns this flow builder's context. - * @return the flow builder context - */ - protected FlowBuilderContext getContext() { - return context; - } - - public void buildVariables() throws FlowBuilderException { - } - - public void buildInputMapper() throws FlowBuilderException { - } - - public void buildStartActions() throws FlowBuilderException { - } - - public abstract void buildStates() throws FlowBuilderException; - - public void buildGlobalTransitions() throws FlowBuilderException { - } - - public void buildEndActions() throws FlowBuilderException { - } - - public void buildOutputMapper() throws FlowBuilderException { - } - - public void buildExceptionHandlers() throws FlowBuilderException { - } - - public Flow getFlow() throws FlowBuilderException { - return flow; - } - - public void dispose() throws FlowBuilderException { - flow = null; - doDispose(); - } - - public boolean hasFlowChanged() { - return false; - } - - public String getFlowResourceString() { - return getClass().getName(); - } - - /** - * Flow builder destruction hook. Does nothing by default. May be overridden by subclasses. - */ - protected void doDispose() { - - } - +/* + * Copyright 2004-2012 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 + * + * https://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.engine.builder.support; + +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.engine.builder.FlowBuilder; +import org.springframework.webflow.engine.builder.FlowBuilderContext; +import org.springframework.webflow.engine.builder.FlowBuilderException; + +/** + * Abstract base implementation of a flow builder defining common functionality needed by most concrete flow builder + * implementations. This class implements all optional parts of the FlowBuilder process as no-op methods. Subclasses are + * only required to implement {@link #buildStates()}. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public abstract class AbstractFlowBuilder implements FlowBuilder { + + /** + * The Flow built by this builder. + */ + private Flow flow; + + /** + * The flow builder context providing access to services needed to build the flow. + */ + private FlowBuilderContext context; + + public void init(FlowBuilderContext context) throws FlowBuilderException { + this.context = context; + doInit(); + flow = createFlow(); + } + + /** + * Flow builder initialization hook. Does nothing by default. May be overridden by subclasses. + */ + protected void doInit() { + + } + + /** + * Factory method that initially creates the flow implementation during flow builder initialization. Simply + * delegates to the configured flow artifact factory by default. + * @return the flow instance, initially created but not yet built + */ + protected Flow createFlow() { + String id = getContext().getFlowId(); + AttributeMap attributes = getContext().getFlowAttributes(); + return getContext().getFlowArtifactFactory().createFlow(id, attributes); + } + + /** + * Returns this flow builder's context. + * @return the flow builder context + */ + protected FlowBuilderContext getContext() { + return context; + } + + public void buildVariables() throws FlowBuilderException { + } + + public void buildInputMapper() throws FlowBuilderException { + } + + public void buildStartActions() throws FlowBuilderException { + } + + public abstract void buildStates() throws FlowBuilderException; + + public void buildGlobalTransitions() throws FlowBuilderException { + } + + public void buildEndActions() throws FlowBuilderException { + } + + public void buildOutputMapper() throws FlowBuilderException { + } + + public void buildExceptionHandlers() throws FlowBuilderException { + } + + public Flow getFlow() throws FlowBuilderException { + return flow; + } + + public void dispose() throws FlowBuilderException { + flow = null; + doDispose(); + } + + public boolean hasFlowChanged() { + return false; + } + + public String getFlowResourceString() { + return getClass().getName(); + } + + /** + * Flow builder destruction hook. Does nothing by default. May be overridden by subclasses. + */ + protected void doDispose() { + + } + } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolver.java index 26747cfa..1c5358c5 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolver.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTargetStateResolver.java @@ -1,77 +1,77 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.builder.support; - -import org.springframework.binding.convert.converters.Converter; -import org.springframework.binding.expression.Expression; -import org.springframework.binding.expression.ExpressionParser; -import org.springframework.binding.expression.support.FluentParserContext; -import org.springframework.util.StringUtils; -import org.springframework.webflow.engine.TargetStateResolver; -import org.springframework.webflow.engine.builder.FlowBuilderContext; -import org.springframework.webflow.engine.support.DefaultTargetStateResolver; -import org.springframework.webflow.execution.RequestContext; - -/** - * Converter that takes an encoded string representation and produces a corresponding {@link TargetStateResolver} - * object. - *

- * This converter supports the following encoded forms: - *

    - *
  • "stateId" - will result in a TargetStateResolver that always resolves the same state.
  • - *
  • "${stateIdExpression} - will result in a TargetStateResolver that resolves the target state by evaluating an - * expression against the request context. The resolved value can be a target state identifier or a custom - * TargetStateResolver to delegate to.
  • - *
- * - * @author Keith Donald - * @author Erwin Vervaet - */ -class TextToTargetStateResolver implements Converter { - - /** - * Context for flow builder services. - */ - private FlowBuilderContext flowBuilderContext; - - /** - * Create a new converter that converts strings to transition target state resolver objects. The given conversion - * service will be used to do all necessary internal conversion (e.g. parsing expression strings). - */ - public TextToTargetStateResolver(FlowBuilderContext flowBuilderContext) { - this.flowBuilderContext = flowBuilderContext; - } - - public Class getSourceClass() { - return String.class; - } - - public Class getTargetClass() { - return TargetStateResolver.class; - } - - public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception { - String targetStateId = (String) source; - if (!StringUtils.hasText(targetStateId)) { - return null; - } - ExpressionParser parser = flowBuilderContext.getExpressionParser(); - Expression expression = parser.parseExpression(targetStateId, - new FluentParserContext().template().evaluate(RequestContext.class).expectResult(String.class)); - return new DefaultTargetStateResolver(expression); - - } +/* + * Copyright 2004-2012 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 + * + * https://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.engine.builder.support; + +import org.springframework.binding.convert.converters.Converter; +import org.springframework.binding.expression.Expression; +import org.springframework.binding.expression.ExpressionParser; +import org.springframework.binding.expression.support.FluentParserContext; +import org.springframework.util.StringUtils; +import org.springframework.webflow.engine.TargetStateResolver; +import org.springframework.webflow.engine.builder.FlowBuilderContext; +import org.springframework.webflow.engine.support.DefaultTargetStateResolver; +import org.springframework.webflow.execution.RequestContext; + +/** + * Converter that takes an encoded string representation and produces a corresponding {@link TargetStateResolver} + * object. + *

+ * This converter supports the following encoded forms: + *

    + *
  • "stateId" - will result in a TargetStateResolver that always resolves the same state.
  • + *
  • "${stateIdExpression} - will result in a TargetStateResolver that resolves the target state by evaluating an + * expression against the request context. The resolved value can be a target state identifier or a custom + * TargetStateResolver to delegate to.
  • + *
+ * + * @author Keith Donald + * @author Erwin Vervaet + */ +class TextToTargetStateResolver implements Converter { + + /** + * Context for flow builder services. + */ + private FlowBuilderContext flowBuilderContext; + + /** + * Create a new converter that converts strings to transition target state resolver objects. The given conversion + * service will be used to do all necessary internal conversion (e.g. parsing expression strings). + */ + public TextToTargetStateResolver(FlowBuilderContext flowBuilderContext) { + this.flowBuilderContext = flowBuilderContext; + } + + public Class getSourceClass() { + return String.class; + } + + public Class getTargetClass() { + return TargetStateResolver.class; + } + + public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception { + String targetStateId = (String) source; + if (!StringUtils.hasText(targetStateId)) { + return null; + } + ExpressionParser parser = flowBuilderContext.getExpressionParser(); + Expression expression = parser.parseExpression(targetStateId, + new FluentParserContext().template().evaluate(RequestContext.class).expectResult(String.class)); + return new DefaultTargetStateResolver(expression); + + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteria.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteria.java index 4aa4b117..12eec303 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteria.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/support/TextToTransitionCriteria.java @@ -1,95 +1,95 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.builder.support; - -import org.springframework.binding.convert.ConversionExecutionException; -import org.springframework.binding.convert.converters.Converter; -import org.springframework.binding.expression.Expression; -import org.springframework.binding.expression.ExpressionParser; -import org.springframework.binding.expression.support.FluentParserContext; -import org.springframework.util.StringUtils; -import org.springframework.webflow.engine.TransitionCriteria; -import org.springframework.webflow.engine.WildcardTransitionCriteria; -import org.springframework.webflow.engine.builder.FlowBuilderContext; -import org.springframework.webflow.engine.support.DefaultTransitionCriteria; -import org.springframework.webflow.execution.RequestContext; - -/** - * Converter that takes an encoded string representation and produces a corresponding TransitionCriteria - * object. - *

- * This converter supports the following encoded forms: - *

    - *
  • "*" - will result in a TransitionCriteria object that matches on everything.
  • - *
  • "eventId" - will result in a TransitionCriteria object that matches given event id.
  • - *
  • "${...}" - will result in a TransitionCriteria object that evaluates given condition, expressed as an expression. - *
  • - *
- * - * @see org.springframework.webflow.engine.TransitionCriteria - * - * @author Keith Donald - * @author Erwin Vervaet - */ -class TextToTransitionCriteria implements Converter { - - /** - * Context for flow builder services. - */ - private FlowBuilderContext flowBuilderContext; - - /** - * Create a new converter that converts strings to transition criteria objects. Custom transition criteria will be - * looked up using given service locator. - */ - public TextToTransitionCriteria(FlowBuilderContext flowBuilderContext) { - this.flowBuilderContext = flowBuilderContext; - } - - public Class getSourceClass() { - return String.class; - } - - public Class getTargetClass() { - return TransitionCriteria.class; - } - - public Object convertSourceToTargetClass(Object source, Class targetClass) { - String encodedCriteria = (String) source; - ExpressionParser parser = flowBuilderContext.getExpressionParser(); - if (!StringUtils.hasText(encodedCriteria) - || WildcardTransitionCriteria.WILDCARD_EVENT_ID.equals(encodedCriteria)) { - return WildcardTransitionCriteria.INSTANCE; - } else { - return createBooleanExpressionTransitionCriteria(encodedCriteria, parser); - } - } - - /** - * Hook method subclasses can override to return a specialized expression evaluating transition criteria - * implementation. - * @param encodedCriteria the encoded transition criteria expression - * @param parser the parser that should parse the expression - * @return the transition criteria object - * @throws ConversionExecutionException when something goes wrong - */ - protected TransitionCriteria createBooleanExpressionTransitionCriteria(String encodedCriteria, - ExpressionParser parser) throws ConversionExecutionException { - Expression expression = parser.parseExpression(encodedCriteria, - new FluentParserContext().template().evaluate(RequestContext.class)); - return new DefaultTransitionCriteria(expression); - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine.builder.support; + +import org.springframework.binding.convert.ConversionExecutionException; +import org.springframework.binding.convert.converters.Converter; +import org.springframework.binding.expression.Expression; +import org.springframework.binding.expression.ExpressionParser; +import org.springframework.binding.expression.support.FluentParserContext; +import org.springframework.util.StringUtils; +import org.springframework.webflow.engine.TransitionCriteria; +import org.springframework.webflow.engine.WildcardTransitionCriteria; +import org.springframework.webflow.engine.builder.FlowBuilderContext; +import org.springframework.webflow.engine.support.DefaultTransitionCriteria; +import org.springframework.webflow.execution.RequestContext; + +/** + * Converter that takes an encoded string representation and produces a corresponding TransitionCriteria + * object. + *

+ * This converter supports the following encoded forms: + *

    + *
  • "*" - will result in a TransitionCriteria object that matches on everything.
  • + *
  • "eventId" - will result in a TransitionCriteria object that matches given event id.
  • + *
  • "${...}" - will result in a TransitionCriteria object that evaluates given condition, expressed as an expression. + *
  • + *
+ * + * @see org.springframework.webflow.engine.TransitionCriteria + * + * @author Keith Donald + * @author Erwin Vervaet + */ +class TextToTransitionCriteria implements Converter { + + /** + * Context for flow builder services. + */ + private FlowBuilderContext flowBuilderContext; + + /** + * Create a new converter that converts strings to transition criteria objects. Custom transition criteria will be + * looked up using given service locator. + */ + public TextToTransitionCriteria(FlowBuilderContext flowBuilderContext) { + this.flowBuilderContext = flowBuilderContext; + } + + public Class getSourceClass() { + return String.class; + } + + public Class getTargetClass() { + return TransitionCriteria.class; + } + + public Object convertSourceToTargetClass(Object source, Class targetClass) { + String encodedCriteria = (String) source; + ExpressionParser parser = flowBuilderContext.getExpressionParser(); + if (!StringUtils.hasText(encodedCriteria) + || WildcardTransitionCriteria.WILDCARD_EVENT_ID.equals(encodedCriteria)) { + return WildcardTransitionCriteria.INSTANCE; + } else { + return createBooleanExpressionTransitionCriteria(encodedCriteria, parser); + } + } + + /** + * Hook method subclasses can override to return a specialized expression evaluating transition criteria + * implementation. + * @param encodedCriteria the encoded transition criteria expression + * @param parser the parser that should parse the expression + * @return the transition criteria object + * @throws ConversionExecutionException when something goes wrong + */ + protected TransitionCriteria createBooleanExpressionTransitionCriteria(String encodedCriteria, + ExpressionParser parser) throws ConversionExecutionException { + Expression expression = parser.parseExpression(encodedCriteria, + new FluentParserContext().template().evaluate(RequestContext.class)); + return new DefaultTransitionCriteria(expression); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactory.java index 3154adc6..726a839a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactory.java @@ -1,173 +1,173 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.impl; - -import java.util.Iterator; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.util.Assert; -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.core.collection.CollectionUtils; -import org.springframework.webflow.core.collection.LocalAttributeMap; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.registry.FlowDefinitionLocator; -import org.springframework.webflow.engine.Flow; -import org.springframework.webflow.execution.FlowExecution; -import org.springframework.webflow.execution.FlowExecutionFactory; -import org.springframework.webflow.execution.FlowExecutionKey; -import org.springframework.webflow.execution.FlowExecutionKeyFactory; -import org.springframework.webflow.execution.factory.FlowExecutionListenerLoader; -import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader; - -/** - * A factory for instances of the {@link FlowExecutionImpl default flow execution} implementation. - * @author Keith Donald - */ -public class FlowExecutionImplFactory implements FlowExecutionFactory { - - private static final Log logger = LogFactory.getLog(FlowExecutionImplFactory.class); - - private AttributeMap executionAttributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP; - - private FlowExecutionListenerLoader executionListenerLoader = StaticFlowExecutionListenerLoader.EMPTY_INSTANCE; - - private FlowExecutionKeyFactory executionKeyFactory = new SimpleFlowExecutionKeyFactory(); - - /** - * Sets the attributes to apply to flow executions created by this factory. Execution attributes may affect flow - * execution behavior. - * @param executionAttributes flow execution system attributes - */ - public void setExecutionAttributes(AttributeMap executionAttributes) { - this.executionAttributes = executionAttributes; - } - - /** - * Sets the strategy for loading listeners that should observe executions of a flow definition. Allows full control - * over what listeners should apply for executions of a flow definition. - */ - public void setExecutionListenerLoader(FlowExecutionListenerLoader executionListenerLoader) { - this.executionListenerLoader = executionListenerLoader; - } - - /** - * Sets the strategy for generating flow execution keys for persistent flow executions. - */ - public void setExecutionKeyFactory(FlowExecutionKeyFactory executionKeyFactory) { - this.executionKeyFactory = executionKeyFactory; - } - - public FlowExecution createFlowExecution(FlowDefinition flowDefinition) { - Assert.isInstanceOf(Flow.class, flowDefinition, "FlowDefinition is of the wrong type: "); - if (logger.isDebugEnabled()) { - logger.debug("Creating new execution of '" + flowDefinition.getId() + "'"); - } - FlowExecutionImpl execution = new FlowExecutionImpl((Flow) flowDefinition); - execution.setAttributes(executionAttributes); - execution.setListeners(executionListenerLoader.getListeners(execution.getDefinition())); - execution.setKeyFactory(executionKeyFactory); - return execution; - } - - public FlowExecution restoreFlowExecution(FlowExecution flowExecution, FlowDefinition flowDefinition, - FlowExecutionKey flowExecutionKey, MutableAttributeMap conversationScope, - FlowDefinitionLocator subflowDefinitionLocator) { - Assert.isInstanceOf(FlowExecutionImpl.class, flowExecution, "FlowExecution is of the wrong type: "); - Assert.isInstanceOf(Flow.class, flowDefinition, "FlowDefinition is of the wrong type: "); - FlowExecutionImpl execution = (FlowExecutionImpl) flowExecution; - Flow flow = (Flow) flowDefinition; - execution.setFlow(flow); - if (execution.hasSessions()) { - FlowSessionImpl rootSession = execution.getRootSession(); - rootSession.setFlow(flow); - rootSession.setState(flow.getStateInstance(rootSession.getStateId())); - if (execution.hasSubflowSessions()) { - for (Iterator it = execution.getSubflowSessionIterator(); it.hasNext();) { - FlowSessionImpl subflowSession = it.next(); - Flow subflowDef = (Flow) subflowDefinitionLocator.getFlowDefinition(subflowSession.getFlowId()); - subflowSession.setFlow(subflowDef); - subflowSession.setState(subflowDef.getStateInstance(subflowSession.getStateId())); - } - } - } - execution.setKey(flowExecutionKey); - if (conversationScope == null) { - conversationScope = new LocalAttributeMap<>(); - } - execution.setConversationScope(conversationScope); - execution.setAttributes(executionAttributes); - execution.setListeners(executionListenerLoader.getListeners(execution.getDefinition())); - execution.setKeyFactory(executionKeyFactory); - return execution; - } - - /** - * Simple key factory suitable for standalone usage and testing. Not expected to be used in a web environment. - */ - private static class SimpleFlowExecutionKeyFactory implements FlowExecutionKeyFactory { - - private int sequence; - - public FlowExecutionKey getKey(FlowExecution execution) { - if (execution.getKey() == null) { - return new SimpleFlowExecutionKey(nextSequence()); - } else { - // keep the same key - return execution.getKey(); - } - } - - public void removeAllFlowExecutionSnapshots(FlowExecution execution) { - } - - public void removeFlowExecutionSnapshot(FlowExecution execution) { - } - - public void updateFlowExecutionSnapshot(FlowExecution execution) { - } - - private synchronized int nextSequence() { - return ++sequence; - } - - private static class SimpleFlowExecutionKey extends FlowExecutionKey { - - private int value; - - public SimpleFlowExecutionKey(int value) { - this.value = value; - } - - public boolean equals(Object o) { - if (!(o instanceof SimpleFlowExecutionKey)) { - SimpleFlowExecutionKey key = (SimpleFlowExecutionKey) o; - return value == key.value; - } - return false; - } - - public int hashCode() { - return value; - } - - public String toString() { - return String.valueOf(value); - } - } - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine.impl; + +import java.util.Iterator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.util.Assert; +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.core.collection.CollectionUtils; +import org.springframework.webflow.core.collection.LocalAttributeMap; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.registry.FlowDefinitionLocator; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.execution.FlowExecution; +import org.springframework.webflow.execution.FlowExecutionFactory; +import org.springframework.webflow.execution.FlowExecutionKey; +import org.springframework.webflow.execution.FlowExecutionKeyFactory; +import org.springframework.webflow.execution.factory.FlowExecutionListenerLoader; +import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader; + +/** + * A factory for instances of the {@link FlowExecutionImpl default flow execution} implementation. + * @author Keith Donald + */ +public class FlowExecutionImplFactory implements FlowExecutionFactory { + + private static final Log logger = LogFactory.getLog(FlowExecutionImplFactory.class); + + private AttributeMap executionAttributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP; + + private FlowExecutionListenerLoader executionListenerLoader = StaticFlowExecutionListenerLoader.EMPTY_INSTANCE; + + private FlowExecutionKeyFactory executionKeyFactory = new SimpleFlowExecutionKeyFactory(); + + /** + * Sets the attributes to apply to flow executions created by this factory. Execution attributes may affect flow + * execution behavior. + * @param executionAttributes flow execution system attributes + */ + public void setExecutionAttributes(AttributeMap executionAttributes) { + this.executionAttributes = executionAttributes; + } + + /** + * Sets the strategy for loading listeners that should observe executions of a flow definition. Allows full control + * over what listeners should apply for executions of a flow definition. + */ + public void setExecutionListenerLoader(FlowExecutionListenerLoader executionListenerLoader) { + this.executionListenerLoader = executionListenerLoader; + } + + /** + * Sets the strategy for generating flow execution keys for persistent flow executions. + */ + public void setExecutionKeyFactory(FlowExecutionKeyFactory executionKeyFactory) { + this.executionKeyFactory = executionKeyFactory; + } + + public FlowExecution createFlowExecution(FlowDefinition flowDefinition) { + Assert.isInstanceOf(Flow.class, flowDefinition, "FlowDefinition is of the wrong type: "); + if (logger.isDebugEnabled()) { + logger.debug("Creating new execution of '" + flowDefinition.getId() + "'"); + } + FlowExecutionImpl execution = new FlowExecutionImpl((Flow) flowDefinition); + execution.setAttributes(executionAttributes); + execution.setListeners(executionListenerLoader.getListeners(execution.getDefinition())); + execution.setKeyFactory(executionKeyFactory); + return execution; + } + + public FlowExecution restoreFlowExecution(FlowExecution flowExecution, FlowDefinition flowDefinition, + FlowExecutionKey flowExecutionKey, MutableAttributeMap conversationScope, + FlowDefinitionLocator subflowDefinitionLocator) { + Assert.isInstanceOf(FlowExecutionImpl.class, flowExecution, "FlowExecution is of the wrong type: "); + Assert.isInstanceOf(Flow.class, flowDefinition, "FlowDefinition is of the wrong type: "); + FlowExecutionImpl execution = (FlowExecutionImpl) flowExecution; + Flow flow = (Flow) flowDefinition; + execution.setFlow(flow); + if (execution.hasSessions()) { + FlowSessionImpl rootSession = execution.getRootSession(); + rootSession.setFlow(flow); + rootSession.setState(flow.getStateInstance(rootSession.getStateId())); + if (execution.hasSubflowSessions()) { + for (Iterator it = execution.getSubflowSessionIterator(); it.hasNext();) { + FlowSessionImpl subflowSession = it.next(); + Flow subflowDef = (Flow) subflowDefinitionLocator.getFlowDefinition(subflowSession.getFlowId()); + subflowSession.setFlow(subflowDef); + subflowSession.setState(subflowDef.getStateInstance(subflowSession.getStateId())); + } + } + } + execution.setKey(flowExecutionKey); + if (conversationScope == null) { + conversationScope = new LocalAttributeMap<>(); + } + execution.setConversationScope(conversationScope); + execution.setAttributes(executionAttributes); + execution.setListeners(executionListenerLoader.getListeners(execution.getDefinition())); + execution.setKeyFactory(executionKeyFactory); + return execution; + } + + /** + * Simple key factory suitable for standalone usage and testing. Not expected to be used in a web environment. + */ + private static class SimpleFlowExecutionKeyFactory implements FlowExecutionKeyFactory { + + private int sequence; + + public FlowExecutionKey getKey(FlowExecution execution) { + if (execution.getKey() == null) { + return new SimpleFlowExecutionKey(nextSequence()); + } else { + // keep the same key + return execution.getKey(); + } + } + + public void removeAllFlowExecutionSnapshots(FlowExecution execution) { + } + + public void removeFlowExecutionSnapshot(FlowExecution execution) { + } + + public void updateFlowExecutionSnapshot(FlowExecution execution) { + } + + private synchronized int nextSequence() { + return ++sequence; + } + + private static class SimpleFlowExecutionKey extends FlowExecutionKey { + + private int value; + + public SimpleFlowExecutionKey(int value) { + this.value = value; + } + + public boolean equals(Object o) { + if (!(o instanceof SimpleFlowExecutionKey)) { + SimpleFlowExecutionKey key = (SimpleFlowExecutionKey) o; + return value == key.value; + } + return false; + } + + public int hashCode() { + return value; + } + + public String toString() { + return String.valueOf(value); + } + } + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/DefaultFlowModelHolder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/DefaultFlowModelHolder.java index 71b773ea..af5acb93 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/DefaultFlowModelHolder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/DefaultFlowModelHolder.java @@ -1,102 +1,102 @@ -/* - * 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 - * - * https://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.engine.model.builder; - -import org.springframework.core.io.Resource; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.webflow.engine.model.FlowModel; -import org.springframework.webflow.engine.model.registry.FlowModelHolder; - -/** - * A flow model holder that can detect changes on an underlying flow model resource and refresh that resource - * automatically. - *

- * This class is thread-safe. - *

- * Note that this {@link FlowModel} holder uses a {@link FlowModelBuilder}. - * - * @see FlowModel - * - * @author Keith Donald - * @author Scott Andrews - */ -public class DefaultFlowModelHolder implements FlowModelHolder { - - private FlowModel flowModel; - - private FlowModelBuilder flowModelBuilder; - - private boolean assembling; - - /** - * Creates a new refreshable flow model holder that uses the configured assembler (GOF director) to drive flow - * assembly, on initial use and on any resource change or refresh. - * @param flowModelBuilder the flow model builder to use - */ - public DefaultFlowModelHolder(FlowModelBuilder flowModelBuilder) { - Assert.notNull(flowModelBuilder, "The flow model builder is required"); - this.flowModelBuilder = flowModelBuilder; - } - - public synchronized FlowModel getFlowModel() { - if (assembling) { - // must return early assembly result for when a flow calls itself recursively - return flowModelBuilder.getFlowModel(); - } - if (flowModel == null) { - assembleFlowModel(); - } else { - if (flowModelBuilder.hasFlowModelResourceChanged()) { - assembleFlowModel(); - } - } - return flowModel; - } - - public Resource getFlowModelResource() { - return flowModelBuilder.getFlowModelResource(); - } - - public boolean hasFlowModelChanged() { - return flowModelBuilder.hasFlowModelResourceChanged(); - } - - public synchronized void refresh() { - assembleFlowModel(); - } - - // internal helpers - - private void assembleFlowModel() throws FlowModelBuilderException { - try { - assembling = true; - flowModelBuilder.init(); - flowModelBuilder.build(); - flowModel = flowModelBuilder.getFlowModel(); - } finally { - try { - flowModelBuilder.dispose(); - } finally { - assembling = false; - } - } - } - - public String toString() { - return new ToStringCreator(this).append("flowModelBuilder", flowModelBuilder).toString(); - } +/* + * 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 + * + * https://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.engine.model.builder; + +import org.springframework.core.io.Resource; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.webflow.engine.model.FlowModel; +import org.springframework.webflow.engine.model.registry.FlowModelHolder; + +/** + * A flow model holder that can detect changes on an underlying flow model resource and refresh that resource + * automatically. + *

+ * This class is thread-safe. + *

+ * Note that this {@link FlowModel} holder uses a {@link FlowModelBuilder}. + * + * @see FlowModel + * + * @author Keith Donald + * @author Scott Andrews + */ +public class DefaultFlowModelHolder implements FlowModelHolder { + + private FlowModel flowModel; + + private FlowModelBuilder flowModelBuilder; + + private boolean assembling; + + /** + * Creates a new refreshable flow model holder that uses the configured assembler (GOF director) to drive flow + * assembly, on initial use and on any resource change or refresh. + * @param flowModelBuilder the flow model builder to use + */ + public DefaultFlowModelHolder(FlowModelBuilder flowModelBuilder) { + Assert.notNull(flowModelBuilder, "The flow model builder is required"); + this.flowModelBuilder = flowModelBuilder; + } + + public synchronized FlowModel getFlowModel() { + if (assembling) { + // must return early assembly result for when a flow calls itself recursively + return flowModelBuilder.getFlowModel(); + } + if (flowModel == null) { + assembleFlowModel(); + } else { + if (flowModelBuilder.hasFlowModelResourceChanged()) { + assembleFlowModel(); + } + } + return flowModel; + } + + public Resource getFlowModelResource() { + return flowModelBuilder.getFlowModelResource(); + } + + public boolean hasFlowModelChanged() { + return flowModelBuilder.hasFlowModelResourceChanged(); + } + + public synchronized void refresh() { + assembleFlowModel(); + } + + // internal helpers + + private void assembleFlowModel() throws FlowModelBuilderException { + try { + assembling = true; + flowModelBuilder.init(); + flowModelBuilder.build(); + flowModel = flowModelBuilder.getFlowModel(); + } finally { + try { + flowModelBuilder.dispose(); + } finally { + assembling = false; + } + } + } + + public String toString() { + return new ToStringCreator(this).append("flowModelBuilder", flowModelBuilder).toString(); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilder.java index 7e912d62..5d6d8156 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilder.java @@ -1,85 +1,85 @@ -/* - * 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 - * - * https://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.engine.model.builder; - -import org.springframework.core.io.Resource; -import org.springframework.webflow.engine.model.FlowModel; - -/** - * Builder interface used to build a flow model. The process of building a flow model consists of the following steps: - *

    - *
  1. Initialize this builder by calling {@link #init()}. - *
  2. Call {@link #build()} to create the flow model. - *
  3. Call {@link #getFlowModel()} to return the fully-built {@link FlowModel} model. - *
  4. Dispose this builder, releasing any resources allocated during the building process by calling {@link #dispose()}. - *
- *

- * Implementations should encapsulate flow construction logic, either for a specific kind of flow, for example, an - * XmlFlowModelBuilder, for building flows from an XML-definition. - *

- * This is a good example of the classic GoF builder pattern. - * - * @see FlowModel - * - * @author Keith Donald - * @author Erwin Vervaet - * @author Scott Andrews - */ -public interface FlowModelBuilder { - - /** - * Initialize this builder. This could cause the builder to open a stream to an externalized resource representing - * the flow definition, for example. - * @throws FlowModelBuilderException an exception occurred building the flow - */ - void init() throws FlowModelBuilderException; - - /** - * Builds any variables initialized by the flow when it starts. - * @throws FlowModelBuilderException an exception occurred building the flow - */ - void build() throws FlowModelBuilderException; - - /** - * Get the fully constructed flow model. Called by the builder's assembler (director) after assembly. When this - * method is called by the assembler, it is expected flow construction has completed and the returned flow model is - * ready for use. - * @throws FlowModelBuilderException an exception occurred building this flow - */ - FlowModel getFlowModel() throws FlowModelBuilderException; - - /** - * Shutdown the builder, releasing any resources it holds. A new flow construction process should start with another - * call to the {@link #init()} method. - * @throws FlowModelBuilderException an exception occurred disposing this flow - */ - void dispose() throws FlowModelBuilderException; - - /** - * Get the underlying flow model resource accessed to build this flow model. Returns null if this builder does not - * construct the flow model from a resource. - * @return the flow model resource - */ - Resource getFlowModelResource(); - - /** - * Returns true if the underlying flow model resource has changed since the last call to {@link #init()}. Always - * returns false if the flow model is not build from a resource. - * @return true if the resource backing the flow model has changed - */ - boolean hasFlowModelResourceChanged(); - +/* + * 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 + * + * https://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.engine.model.builder; + +import org.springframework.core.io.Resource; +import org.springframework.webflow.engine.model.FlowModel; + +/** + * Builder interface used to build a flow model. The process of building a flow model consists of the following steps: + *

    + *
  1. Initialize this builder by calling {@link #init()}. + *
  2. Call {@link #build()} to create the flow model. + *
  3. Call {@link #getFlowModel()} to return the fully-built {@link FlowModel} model. + *
  4. Dispose this builder, releasing any resources allocated during the building process by calling {@link #dispose()}. + *
+ *

+ * Implementations should encapsulate flow construction logic, either for a specific kind of flow, for example, an + * XmlFlowModelBuilder, for building flows from an XML-definition. + *

+ * This is a good example of the classic GoF builder pattern. + * + * @see FlowModel + * + * @author Keith Donald + * @author Erwin Vervaet + * @author Scott Andrews + */ +public interface FlowModelBuilder { + + /** + * Initialize this builder. This could cause the builder to open a stream to an externalized resource representing + * the flow definition, for example. + * @throws FlowModelBuilderException an exception occurred building the flow + */ + void init() throws FlowModelBuilderException; + + /** + * Builds any variables initialized by the flow when it starts. + * @throws FlowModelBuilderException an exception occurred building the flow + */ + void build() throws FlowModelBuilderException; + + /** + * Get the fully constructed flow model. Called by the builder's assembler (director) after assembly. When this + * method is called by the assembler, it is expected flow construction has completed and the returned flow model is + * ready for use. + * @throws FlowModelBuilderException an exception occurred building this flow + */ + FlowModel getFlowModel() throws FlowModelBuilderException; + + /** + * Shutdown the builder, releasing any resources it holds. A new flow construction process should start with another + * call to the {@link #init()} method. + * @throws FlowModelBuilderException an exception occurred disposing this flow + */ + void dispose() throws FlowModelBuilderException; + + /** + * Get the underlying flow model resource accessed to build this flow model. Returns null if this builder does not + * construct the flow model from a resource. + * @return the flow model resource + */ + Resource getFlowModelResource(); + + /** + * Returns true if the underlying flow model resource has changed since the last call to {@link #init()}. Always + * returns false if the flow model is not build from a resource. + * @return true if the resource backing the flow model has changed + */ + boolean hasFlowModelResourceChanged(); + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilderException.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilderException.java index 647bc514..5fe04fd5 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilderException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilderException.java @@ -1,46 +1,46 @@ -/* - * 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 - * - * https://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.engine.model.builder; - -import org.springframework.webflow.core.FlowException; - -/** - * Exception thrown to indicate a problem while building a flow model. - * - * @see FlowModelBuilder - * - * @author Erwin Vervaet - * @author Scott Andrews - */ -public class FlowModelBuilderException extends FlowException { - - /** - * Create a new flow model builder exception. - * @param message descriptive message - */ - public FlowModelBuilderException(String message) { - super(message); - } - - /** - * Create a new flow model builder exception. - * @param message descriptive message - * @param cause the underlying cause of this exception - */ - public FlowModelBuilderException(String message, Throwable cause) { - super(message, cause); - } +/* + * 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 + * + * https://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.engine.model.builder; + +import org.springframework.webflow.core.FlowException; + +/** + * Exception thrown to indicate a problem while building a flow model. + * + * @see FlowModelBuilder + * + * @author Erwin Vervaet + * @author Scott Andrews + */ +public class FlowModelBuilderException extends FlowException { + + /** + * Create a new flow model builder exception. + * @param message descriptive message + */ + public FlowModelBuilderException(String message) { + super(message); + } + + /** + * Create a new flow model builder exception. + * @param message descriptive message + * @param cause the underlying cause of this exception + */ + public FlowModelBuilderException(String message, Throwable cause) { + super(message, cause); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/DocumentLoader.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/DocumentLoader.java index bc2f15ff..2d4f1e62 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/DocumentLoader.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/DocumentLoader.java @@ -1,42 +1,42 @@ -/* - * 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 - * - * https://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.engine.model.builder.xml; - -import java.io.IOException; - -import javax.xml.parsers.ParserConfigurationException; - -import org.springframework.core.io.Resource; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - -/** - * A generic strategy interface encapsulating the logic to load an XML-based document. - * - * @author Keith Donald - */ -public interface DocumentLoader { - - /** - * Load the XML-based document from the external resource. - * @param resource the document resource - * @return the loaded (parsed) document - * @throws IOException an exception occured accessing the resource input stream - * @throws ParserConfigurationException an exception occured building the document parser - * @throws SAXException a error occured during document parsing - */ - Document loadDocument(Resource resource) throws IOException, ParserConfigurationException, SAXException; +/* + * 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 + * + * https://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.engine.model.builder.xml; + +import java.io.IOException; + +import javax.xml.parsers.ParserConfigurationException; + +import org.springframework.core.io.Resource; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; + +/** + * A generic strategy interface encapsulating the logic to load an XML-based document. + * + * @author Keith Donald + */ +public interface DocumentLoader { + + /** + * Load the XML-based document from the external resource. + * @param resource the document resource + * @return the loaded (parsed) document + * @throws IOException an exception occured accessing the resource input stream + * @throws ParserConfigurationException an exception occured building the document parser + * @throws SAXException a error occured during document parsing + */ + Document loadDocument(Resource resource) throws IOException, ParserConfigurationException, SAXException; } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/WebFlowEntityResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/WebFlowEntityResolver.java index b3335637..f06b563e 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/WebFlowEntityResolver.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/WebFlowEntityResolver.java @@ -1,74 +1,74 @@ -/* - * Copyright 2004-2018 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 - * - * https://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.engine.model.builder.xml; - -import java.io.IOException; - -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.xml.sax.EntityResolver; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * EntityResolver implementation for the Spring Web Flow XML Schema. This will load the XSD from the classpath. - *

- * The xmlns of the XSD expected to be resolved: - * - *

- *     <?xml version="1.0" encoding="UTF-8"?>
- *     <flow xmlns="http://www.springframework.org/schema/webflow"
- *           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- *           xsi:schemaLocation="http://www.springframework.org/schema/webflow
- *                               http://www.springframework.org/schema/webflow/spring-webflow.xsd">
- * 
- * - * @author Erwin Vervaet - * @author Ben Hale - */ -class WebFlowEntityResolver implements EntityResolver { - - private static final String SPRING_WEBFLOW_XSD = "spring-webflow.xsd"; - - private static final String[] WEBFLOW_VERSIONS = new String[] { "spring-webflow-2.4", "spring-webflow-2.0" }; - - - public InputSource resolveEntity(String publicId, String systemId) { - if (systemId != null && systemId.contains(SPRING_WEBFLOW_XSD)) { - return createInputSource(publicId, systemId, SPRING_WEBFLOW_XSD); - } - for (String element : WEBFLOW_VERSIONS) { - if (systemId != null && systemId.indexOf(element) > systemId.lastIndexOf("/")) { - return createInputSource(publicId, systemId, SPRING_WEBFLOW_XSD); - } - } - // let the parser handle it - return null; - } - - private InputSource createInputSource(String publicId, String systemId, String fileName) { - try { - Resource resource = new ClassPathResource(fileName, getClass()); - InputSource source = new InputSource(resource.getInputStream()); - source.setPublicId(publicId); - source.setSystemId(systemId); - return source; - } catch (IOException ex) { - // fall through below - } - return null; - } -} +/* + * Copyright 2004-2018 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 + * + * https://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.engine.model.builder.xml; + +import java.io.IOException; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * EntityResolver implementation for the Spring Web Flow XML Schema. This will load the XSD from the classpath. + *

+ * The xmlns of the XSD expected to be resolved: + * + *

+ *     <?xml version="1.0" encoding="UTF-8"?>
+ *     <flow xmlns="http://www.springframework.org/schema/webflow"
+ *           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ *           xsi:schemaLocation="http://www.springframework.org/schema/webflow
+ *                               http://www.springframework.org/schema/webflow/spring-webflow.xsd">
+ * 
+ * + * @author Erwin Vervaet + * @author Ben Hale + */ +class WebFlowEntityResolver implements EntityResolver { + + private static final String SPRING_WEBFLOW_XSD = "spring-webflow.xsd"; + + private static final String[] WEBFLOW_VERSIONS = new String[] { "spring-webflow-2.4", "spring-webflow-2.0" }; + + + public InputSource resolveEntity(String publicId, String systemId) { + if (systemId != null && systemId.contains(SPRING_WEBFLOW_XSD)) { + return createInputSource(publicId, systemId, SPRING_WEBFLOW_XSD); + } + for (String element : WEBFLOW_VERSIONS) { + if (systemId != null && systemId.indexOf(element) > systemId.lastIndexOf("/")) { + return createInputSource(publicId, systemId, SPRING_WEBFLOW_XSD); + } + } + // let the parser handle it + return null; + } + + private InputSource createInputSource(String publicId, String systemId, String fileName) { + try { + Resource resource = new ClassPathResource(fileName, getClass()); + InputSource source = new InputSource(resource.getInputStream()); + source.setPublicId(publicId); + source.setSystemId(systemId); + return source; + } catch (IOException ex) { + // fall through below + } + return null; + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelHolder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelHolder.java index d59ad675..8e21f848 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelHolder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelHolder.java @@ -1,55 +1,55 @@ -/* - * 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 - * - * https://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.engine.model.registry; - -import org.springframework.core.io.Resource; -import org.springframework.webflow.engine.model.FlowModel; - -/** - * A holder holding a reference to a Flow model. Provides a layer of indirection, enabling things like "hot-reloadable" - * flow models. - * - * @see FlowModelRegistry#registerFlowModel(String, FlowModelHolder) - * - * @author Keith Donald - * @author Scott Andrews - */ -public interface FlowModelHolder { - - /** - * Returns the flow model held by this holder. Calling this method the first time may trigger flow model assembly. - */ - FlowModel getFlowModel(); - - /** - * Has the underlying flow model changed since it was last accessed via a call to {@link #getFlowModel()}. - * @return true if yes, false if not - */ - boolean hasFlowModelChanged(); - - /** - * Returns the underlying resource defining the flow model. - * @return the flow model resource - */ - Resource getFlowModelResource(); - - /** - * Refresh the flow model held by this holder. Calling this method typically triggers flow re-assembly, which may - * include a refresh from an externalized resource such as a file. - */ - void refresh(); - +/* + * 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 + * + * https://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.engine.model.registry; + +import org.springframework.core.io.Resource; +import org.springframework.webflow.engine.model.FlowModel; + +/** + * A holder holding a reference to a Flow model. Provides a layer of indirection, enabling things like "hot-reloadable" + * flow models. + * + * @see FlowModelRegistry#registerFlowModel(String, FlowModelHolder) + * + * @author Keith Donald + * @author Scott Andrews + */ +public interface FlowModelHolder { + + /** + * Returns the flow model held by this holder. Calling this method the first time may trigger flow model assembly. + */ + FlowModel getFlowModel(); + + /** + * Has the underlying flow model changed since it was last accessed via a call to {@link #getFlowModel()}. + * @return true if yes, false if not + */ + boolean hasFlowModelChanged(); + + /** + * Returns the underlying resource defining the flow model. + * @return the flow model resource + */ + Resource getFlowModelResource(); + + /** + * Refresh the flow model held by this holder. Calling this method typically triggers flow re-assembly, which may + * include a refresh from an externalized resource such as a file. + */ + void refresh(); + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelHolderLocator.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelHolderLocator.java index 6d2c4053..cc336197 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelHolderLocator.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelHolderLocator.java @@ -1,36 +1,36 @@ -/* - * Copyright 2004-2015 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 - * - * https://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.engine.model.registry; - -/** - * A companion to {@link FlowModelLocator} for access to the FlowModelHolder - * wrapping the FlowModel. - * - * @author Rossen Stoyanchev - * @since 2.4.2 - */ -public interface FlowModelHolderLocator { - - /** - * Lookup the FlowModelHolder with the specified id. - * @param id the flow model identifier - * @return the flow model holder - * @throws NoSuchFlowModelException when the flow model with the specified - * id does not exist - */ - FlowModelHolder getFlowModelHolder(String id) throws NoSuchFlowModelException; - -} +/* + * Copyright 2004-2015 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 + * + * https://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.engine.model.registry; + +/** + * A companion to {@link FlowModelLocator} for access to the FlowModelHolder + * wrapping the FlowModel. + * + * @author Rossen Stoyanchev + * @since 2.4.2 + */ +public interface FlowModelHolderLocator { + + /** + * Lookup the FlowModelHolder with the specified id. + * @param id the flow model identifier + * @return the flow model holder + * @throws NoSuchFlowModelException when the flow model with the specified + * id does not exist + */ + FlowModelHolder getFlowModelHolder(String id) throws NoSuchFlowModelException; + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelLocator.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelLocator.java index c3e1d96f..37235b1c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelLocator.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/FlowModelLocator.java @@ -1,37 +1,37 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.model.registry; - -import org.springframework.webflow.engine.model.FlowModel; - -/** - * A runtime service locator interface for retrieving flow definitions by id. Flow locators are needed by - * flow executors at runtime to retrieve flow models to support loading flow definitions. - * - * @author Keith Donald - * @author Erwin Vervaet - * @author Scott Andrews - */ -public interface FlowModelLocator { - - /** - * Lookup the flow model with the specified id. - * @param id the flow model identifier - * @return the flow mode - * @throws NoSuchFlowModelException when the flow model with the specified id does not exist - */ - FlowModel getFlowModel(String id) throws NoSuchFlowModelException; -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine.model.registry; + +import org.springframework.webflow.engine.model.FlowModel; + +/** + * A runtime service locator interface for retrieving flow definitions by id. Flow locators are needed by + * flow executors at runtime to retrieve flow models to support loading flow definitions. + * + * @author Keith Donald + * @author Erwin Vervaet + * @author Scott Andrews + */ +public interface FlowModelLocator { + + /** + * Lookup the flow model with the specified id. + * @param id the flow model identifier + * @return the flow mode + * @throws NoSuchFlowModelException when the flow model with the specified id does not exist + */ + FlowModel getFlowModel(String id) throws NoSuchFlowModelException; +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/NoSuchFlowModelException.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/NoSuchFlowModelException.java index 72e843eb..8d934856 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/NoSuchFlowModelException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/registry/NoSuchFlowModelException.java @@ -1,49 +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 - * - * https://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.engine.model.registry; - -import org.springframework.webflow.core.FlowException; - -/** - * Thrown when no flow model was found during a lookup operation by a flow locator. - * - * @author Keith Donald - * @author Erwin Vervaet - * @author Scott Andrews - */ -public class NoSuchFlowModelException extends FlowException { - - /** - * The id of the flow model that could not be located. - */ - private String flowModelId; - - /** - * Creates an exception indicating a flow model could not be found. - * @param flowModelId the flow model id - */ - public NoSuchFlowModelException(String flowModelId) { - super("No flow model '" + flowModelId + "' found"); - this.flowModelId = flowModelId; - } - - /** - * Returns the id of the flow model that could not be found. - */ - public String getFlowModelId() { - return flowModelId; - } +/* + * 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 + * + * https://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.engine.model.registry; + +import org.springframework.webflow.core.FlowException; + +/** + * Thrown when no flow model was found during a lookup operation by a flow locator. + * + * @author Keith Donald + * @author Erwin Vervaet + * @author Scott Andrews + */ +public class NoSuchFlowModelException extends FlowException { + + /** + * The id of the flow model that could not be located. + */ + private String flowModelId; + + /** + * Creates an exception indicating a flow model could not be found. + * @param flowModelId the flow model id + */ + public NoSuchFlowModelException(String flowModelId) { + super("No flow model '" + flowModelId + "' found"); + this.flowModelId = flowModelId; + } + + /** + * Returns the id of the flow model that could not be found. + */ + public String getFlowModelId() { + return flowModelId; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionTransitionCriteria.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionTransitionCriteria.java index 7a969414..7527fef1 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionTransitionCriteria.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/ActionTransitionCriteria.java @@ -1,94 +1,94 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.support; - -import org.springframework.webflow.engine.TransitionCriteria; -import org.springframework.webflow.execution.Action; -import org.springframework.webflow.execution.ActionExecutor; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.RequestContext; - -/** - * A transition criteria that will execute an action when tested and return true if the action's result is - * equal to the 'trueEventId', false otherwise. - *

- * This effectively adapts an Action to a TransitionCriteria. - * - * @see org.springframework.webflow.execution.Action - * @see org.springframework.webflow.engine.TransitionCriteria - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class ActionTransitionCriteria implements TransitionCriteria { - - /** - * The result event id that should map to a true return value. - */ - private String[] trueEventIds = new String[] { "success", "yes", "true" }; - - /** - * The action to execute when the criteria is tested, annotated with usage attributes. - */ - private Action action; - - /** - * Create action transition criteria delegating to the specified action. - * @param action the action - */ - public ActionTransitionCriteria(Action action) { - this.action = action; - } - - /** - * Returns the action result eventIds that should cause this criteria to return true (it will return - * false otherwise). Defaults to "success". - */ - public String[] getTrueEventIds() { - return trueEventIds; - } - - /** - * Sets the action result eventIds that should cause this precondition to return true (it will return - * false otherwise). - * @param trueEventIds the true result event IDs - */ - public void setTrueEventIds(String... trueEventIds) { - this.trueEventIds = trueEventIds; - } - - /** - * Returns the action wrapped by this object. - * @return the action - */ - protected Action getAction() { - return action; - } - - public boolean test(RequestContext context) { - Event result = ActionExecutor.execute(getAction(), context); - return result != null && isTrueEvent(result.getId()); - } - - private boolean isTrueEvent(String eventId) { - for (String trueEventId : trueEventIds) { - if (trueEventId.equals(eventId)) { - return true; - } - } - return false; - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine.support; + +import org.springframework.webflow.engine.TransitionCriteria; +import org.springframework.webflow.execution.Action; +import org.springframework.webflow.execution.ActionExecutor; +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.execution.RequestContext; + +/** + * A transition criteria that will execute an action when tested and return true if the action's result is + * equal to the 'trueEventId', false otherwise. + *

+ * This effectively adapts an Action to a TransitionCriteria. + * + * @see org.springframework.webflow.execution.Action + * @see org.springframework.webflow.engine.TransitionCriteria + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class ActionTransitionCriteria implements TransitionCriteria { + + /** + * The result event id that should map to a true return value. + */ + private String[] trueEventIds = new String[] { "success", "yes", "true" }; + + /** + * The action to execute when the criteria is tested, annotated with usage attributes. + */ + private Action action; + + /** + * Create action transition criteria delegating to the specified action. + * @param action the action + */ + public ActionTransitionCriteria(Action action) { + this.action = action; + } + + /** + * Returns the action result eventIds that should cause this criteria to return true (it will return + * false otherwise). Defaults to "success". + */ + public String[] getTrueEventIds() { + return trueEventIds; + } + + /** + * Sets the action result eventIds that should cause this precondition to return true (it will return + * false otherwise). + * @param trueEventIds the true result event IDs + */ + public void setTrueEventIds(String... trueEventIds) { + this.trueEventIds = trueEventIds; + } + + /** + * Returns the action wrapped by this object. + * @return the action + */ + protected Action getAction() { + return action; + } + + public boolean test(RequestContext context) { + Event result = ActionExecutor.execute(getAction(), context); + return result != null && isTrueEvent(result.getId()); + } + + private boolean isTrueEvent(String eventId) { + for (String trueEventId : trueEventIds) { + if (trueEventId.equals(eventId)) { + return true; + } + } + return false; + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/DefaultTargetStateResolver.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/DefaultTargetStateResolver.java index daf821b6..8480f323 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/DefaultTargetStateResolver.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/DefaultTargetStateResolver.java @@ -1,69 +1,69 @@ -/* - * 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 - * - * https://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.engine.support; - -import org.springframework.binding.expression.Expression; -import org.springframework.binding.expression.support.StaticExpression; -import org.springframework.util.Assert; -import org.springframework.webflow.engine.Flow; -import org.springframework.webflow.engine.State; -import org.springframework.webflow.engine.TargetStateResolver; -import org.springframework.webflow.engine.Transition; -import org.springframework.webflow.execution.RequestContext; - -/** - * A transition target state resolver that evaluates an expression to resolve the target state. The default - * implementation. - * - * @author Keith Donald - */ -public class DefaultTargetStateResolver implements TargetStateResolver { - - /** - * The expression for the target state identifier. - */ - private Expression targetStateIdExpression; - - /** - * Creates a new target state resolver that always returns the same target state id. - * @param targetStateId a static target target state - */ - public DefaultTargetStateResolver(String targetStateId) { - this(new StaticExpression(targetStateId)); - } - - /** - * Creates a new target state resolver. - * @param targetStateIdExpression the target state expression - */ - public DefaultTargetStateResolver(Expression targetStateIdExpression) { - Assert.notNull(targetStateIdExpression, "The target state id expression is required"); - this.targetStateIdExpression = targetStateIdExpression; - } - - public State resolveTargetState(Transition transition, State sourceState, RequestContext context) { - String targetStateId = (String) targetStateIdExpression.getValue(context); - if (targetStateId != null) { - return ((Flow) context.getActiveFlow()).getStateInstance(targetStateId); - } else { - return null; - } - } - - public String toString() { - return targetStateIdExpression.toString(); - } +/* + * 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 + * + * https://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.engine.support; + +import org.springframework.binding.expression.Expression; +import org.springframework.binding.expression.support.StaticExpression; +import org.springframework.util.Assert; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.engine.State; +import org.springframework.webflow.engine.TargetStateResolver; +import org.springframework.webflow.engine.Transition; +import org.springframework.webflow.execution.RequestContext; + +/** + * A transition target state resolver that evaluates an expression to resolve the target state. The default + * implementation. + * + * @author Keith Donald + */ +public class DefaultTargetStateResolver implements TargetStateResolver { + + /** + * The expression for the target state identifier. + */ + private Expression targetStateIdExpression; + + /** + * Creates a new target state resolver that always returns the same target state id. + * @param targetStateId a static target target state + */ + public DefaultTargetStateResolver(String targetStateId) { + this(new StaticExpression(targetStateId)); + } + + /** + * Creates a new target state resolver. + * @param targetStateIdExpression the target state expression + */ + public DefaultTargetStateResolver(Expression targetStateIdExpression) { + Assert.notNull(targetStateIdExpression, "The target state id expression is required"); + this.targetStateIdExpression = targetStateIdExpression; + } + + public State resolveTargetState(Transition transition, State sourceState, RequestContext context) { + String targetStateId = (String) targetStateIdExpression.getValue(context); + if (targetStateId != null) { + return ((Flow) context.getActiveFlow()).getStateInstance(targetStateId); + } else { + return null; + } + } + + public String toString() { + return targetStateIdExpression.toString(); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/DefaultTransitionCriteria.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/DefaultTransitionCriteria.java index b07393b5..160849b1 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/DefaultTransitionCriteria.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/DefaultTransitionCriteria.java @@ -1,62 +1,62 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.support; - -import org.springframework.binding.expression.Expression; -import org.springframework.util.Assert; -import org.springframework.webflow.engine.TransitionCriteria; -import org.springframework.webflow.execution.RequestContext; - -/** - * Transition criteria that tests the value of an expression. The expression is used to express a condition that guards - * transition execution in a web flow. Expressions will be evaluated against the request context. Boolean, string, and - * custom TransitonCriteria evaluation results are supported. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class DefaultTransitionCriteria implements TransitionCriteria { - - /** - * The expression evaluator to use. - */ - private Expression expression; - - /** - * Create a new expression based transition criteria object. - * @param expression the expression evaluator testing the criteria - */ - public DefaultTransitionCriteria(Expression expression) { - Assert.notNull(expression, "The transition criteria expression to test is required"); - this.expression = expression; - } - - public boolean test(RequestContext context) { - Object result = expression.getValue(context); - if (result == null) { - return false; - } else if (result instanceof Boolean) { - return (Boolean) result; - } else { - String eventId = String.valueOf(result); - return context.getCurrentEvent().getId().equals(eventId); - } - } - - public String toString() { - return expression.toString(); - } +/* + * Copyright 2004-2012 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 + * + * https://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.engine.support; + +import org.springframework.binding.expression.Expression; +import org.springframework.util.Assert; +import org.springframework.webflow.engine.TransitionCriteria; +import org.springframework.webflow.execution.RequestContext; + +/** + * Transition criteria that tests the value of an expression. The expression is used to express a condition that guards + * transition execution in a web flow. Expressions will be evaluated against the request context. Boolean, string, and + * custom TransitonCriteria evaluation results are supported. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class DefaultTransitionCriteria implements TransitionCriteria { + + /** + * The expression evaluator to use. + */ + private Expression expression; + + /** + * Create a new expression based transition criteria object. + * @param expression the expression evaluator testing the criteria + */ + public DefaultTransitionCriteria(Expression expression) { + Assert.notNull(expression, "The transition criteria expression to test is required"); + this.expression = expression; + } + + public boolean test(RequestContext context) { + Object result = expression.getValue(context); + if (result == null) { + return false; + } else if (result instanceof Boolean) { + return (Boolean) result; + } else { + String eventId = String.valueOf(result); + return context.getCurrentEvent().getId().equals(eventId); + } + } + + public String toString() { + return expression.toString(); + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/GenericSubflowAttributeMapper.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/GenericSubflowAttributeMapper.java index 305c5d85..0dfb727e 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/GenericSubflowAttributeMapper.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/GenericSubflowAttributeMapper.java @@ -1,80 +1,80 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.support; - -import java.io.Serializable; - -import org.springframework.binding.mapping.Mapper; -import org.springframework.binding.mapping.MappingResults; -import org.springframework.core.style.ToStringCreator; -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.core.collection.LocalAttributeMap; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.engine.FlowInputMappingException; -import org.springframework.webflow.engine.FlowOutputMappingException; -import org.springframework.webflow.engine.SubflowAttributeMapper; -import org.springframework.webflow.execution.RequestContext; - -/** - * Simple flow attribute mapper that holds an input and output mapper strategy. - * - * @author Keith Donald - */ -public final class GenericSubflowAttributeMapper implements SubflowAttributeMapper, Serializable { - - private final Mapper inputMapper; - - private final Mapper outputMapper; - - /** - * Create a new flow attribute mapper using given mapping strategies. - * @param inputMapper the input mapping strategy - * @param outputMapper the output mapping strategy - */ - public GenericSubflowAttributeMapper(Mapper inputMapper, Mapper outputMapper) { - this.inputMapper = inputMapper; - this.outputMapper = outputMapper; - } - - public MutableAttributeMap createSubflowInput(RequestContext context) { - if (inputMapper != null) { - LocalAttributeMap input = new LocalAttributeMap<>(); - MappingResults results = inputMapper.map(context, input); - if (results != null && results.hasErrorResults()) { - throw new FlowInputMappingException(context.getActiveFlow().getId(), context.getCurrentState().getId(), - results); - } - return input; - } else { - return new LocalAttributeMap<>(); - } - } - - public void mapSubflowOutput(AttributeMap output, RequestContext context) { - if (outputMapper != null && output != null) { - MappingResults results = outputMapper.map(output, context); - if (results != null && results.hasErrorResults()) { - throw new FlowOutputMappingException(context.getActiveFlow().getId(), - context.getCurrentState().getId(), results); - } - } - } - - public String toString() { - return new ToStringCreator(this).append("inputMapper", inputMapper).append("outputMapper", outputMapper) - .toString(); - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine.support; + +import java.io.Serializable; + +import org.springframework.binding.mapping.Mapper; +import org.springframework.binding.mapping.MappingResults; +import org.springframework.core.style.ToStringCreator; +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.core.collection.LocalAttributeMap; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.engine.FlowInputMappingException; +import org.springframework.webflow.engine.FlowOutputMappingException; +import org.springframework.webflow.engine.SubflowAttributeMapper; +import org.springframework.webflow.execution.RequestContext; + +/** + * Simple flow attribute mapper that holds an input and output mapper strategy. + * + * @author Keith Donald + */ +public final class GenericSubflowAttributeMapper implements SubflowAttributeMapper, Serializable { + + private final Mapper inputMapper; + + private final Mapper outputMapper; + + /** + * Create a new flow attribute mapper using given mapping strategies. + * @param inputMapper the input mapping strategy + * @param outputMapper the output mapping strategy + */ + public GenericSubflowAttributeMapper(Mapper inputMapper, Mapper outputMapper) { + this.inputMapper = inputMapper; + this.outputMapper = outputMapper; + } + + public MutableAttributeMap createSubflowInput(RequestContext context) { + if (inputMapper != null) { + LocalAttributeMap input = new LocalAttributeMap<>(); + MappingResults results = inputMapper.map(context, input); + if (results != null && results.hasErrorResults()) { + throw new FlowInputMappingException(context.getActiveFlow().getId(), context.getCurrentState().getId(), + results); + } + return input; + } else { + return new LocalAttributeMap<>(); + } + } + + public void mapSubflowOutput(AttributeMap output, RequestContext context) { + if (outputMapper != null && output != null) { + MappingResults results = outputMapper.map(output, context); + if (results != null && results.hasErrorResults()) { + throw new FlowOutputMappingException(context.getActiveFlow().getId(), + context.getCurrentState().getId(), results); + } + } + } + + public String toString() { + return new ToStringCreator(this).append("inputMapper", inputMapper).append("outputMapper", outputMapper) + .toString(); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/NotTransitionCriteria.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/NotTransitionCriteria.java index 3d1f792e..e6158e61 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/NotTransitionCriteria.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/NotTransitionCriteria.java @@ -1,50 +1,50 @@ -/* - * 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 - * - * https://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.engine.support; - -import org.springframework.util.Assert; -import org.springframework.webflow.engine.TransitionCriteria; -import org.springframework.webflow.execution.RequestContext; - -/** - * Transition criteria that negates the result of the evaluation of another criteria object. - * - * @author Keith Donald - */ -public class NotTransitionCriteria implements TransitionCriteria { - - /** - * The criteria to negate. - */ - private TransitionCriteria criteria; - - /** - * Create a new transition criteria object that will negate the result of given criteria object. - * @param criteria the criteria to negate - */ - public NotTransitionCriteria(TransitionCriteria criteria) { - Assert.notNull(criteria, "The criteria object to negate is required"); - this.criteria = criteria; - } - - public boolean test(RequestContext context) { - return !criteria.test(context); - } - - public String toString() { - return "[not(" + criteria + ")]"; - } +/* + * 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 + * + * https://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.engine.support; + +import org.springframework.util.Assert; +import org.springframework.webflow.engine.TransitionCriteria; +import org.springframework.webflow.execution.RequestContext; + +/** + * Transition criteria that negates the result of the evaluation of another criteria object. + * + * @author Keith Donald + */ +public class NotTransitionCriteria implements TransitionCriteria { + + /** + * The criteria to negate. + */ + private TransitionCriteria criteria; + + /** + * Create a new transition criteria object that will negate the result of given criteria object. + * @param criteria the criteria to negate + */ + public NotTransitionCriteria(TransitionCriteria criteria) { + Assert.notNull(criteria, "The criteria object to negate is required"); + this.criteria = criteria; + } + + public boolean test(RequestContext context) { + return !criteria.test(context); + } + + public String toString() { + return "[not(" + criteria + ")]"; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/TransitionCriteriaChain.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/TransitionCriteriaChain.java index 674a2199..9a7c8fb8 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/TransitionCriteriaChain.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/TransitionCriteriaChain.java @@ -1,95 +1,95 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.support; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -import org.springframework.core.style.ToStringCreator; -import org.springframework.webflow.engine.TransitionCriteria; -import org.springframework.webflow.engine.WildcardTransitionCriteria; -import org.springframework.webflow.execution.Action; -import org.springframework.webflow.execution.RequestContext; - -/** - * An ordered chain of TransitionCriteria. Iterates over each element in the chain, continues until one - * returns false or the list is exhausted. So in effect it will do a logical AND between the contained criteria. - * - * @author Keith Donald - */ -public class TransitionCriteriaChain implements TransitionCriteria { - - /** - * The ordered chain of TransitionCriteria objects. - */ - private List criteriaChain = new LinkedList<>(); - - /** - * Creates an initially empty transition criteria chain. - * @see #add(TransitionCriteria) - */ - public TransitionCriteriaChain() { - } - - /** - * Creates a transition criteria chain with the specified criteria. - * @param criteria the criteria - */ - public TransitionCriteriaChain(TransitionCriteria... criteria) { - criteriaChain.addAll(Arrays.asList(criteria)); - } - - /** - * Add given criteria object to the end of the chain. - * @param criteria the criteria - * @return this object, so multiple criteria can be added in a single statement - */ - public TransitionCriteriaChain add(TransitionCriteria criteria) { - this.criteriaChain.add(criteria); - return this; - } - - public boolean test(RequestContext context) { - for (TransitionCriteria criteria : criteriaChain) { - if (!criteria.test(context)) { - return false; - } - } - return true; - } - - public String toString() { - return new ToStringCreator(this).append("criteriaChain", criteriaChain).toString(); - } - - // static helpers - - /** - * Create a transition criteria chain chaining given list of actions. - * @param actions the actions (and their execution properties) to chain together - */ - public static TransitionCriteria criteriaChainFor(Action... actions) { - if (actions == null || actions.length == 0) { - return WildcardTransitionCriteria.INSTANCE; - } - TransitionCriteriaChain chain = new TransitionCriteriaChain(); - for (Action action : actions) { - chain.add(new ActionTransitionCriteria(action)); - } - return chain; - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.engine.support; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import org.springframework.core.style.ToStringCreator; +import org.springframework.webflow.engine.TransitionCriteria; +import org.springframework.webflow.engine.WildcardTransitionCriteria; +import org.springframework.webflow.execution.Action; +import org.springframework.webflow.execution.RequestContext; + +/** + * An ordered chain of TransitionCriteria. Iterates over each element in the chain, continues until one + * returns false or the list is exhausted. So in effect it will do a logical AND between the contained criteria. + * + * @author Keith Donald + */ +public class TransitionCriteriaChain implements TransitionCriteria { + + /** + * The ordered chain of TransitionCriteria objects. + */ + private List criteriaChain = new LinkedList<>(); + + /** + * Creates an initially empty transition criteria chain. + * @see #add(TransitionCriteria) + */ + public TransitionCriteriaChain() { + } + + /** + * Creates a transition criteria chain with the specified criteria. + * @param criteria the criteria + */ + public TransitionCriteriaChain(TransitionCriteria... criteria) { + criteriaChain.addAll(Arrays.asList(criteria)); + } + + /** + * Add given criteria object to the end of the chain. + * @param criteria the criteria + * @return this object, so multiple criteria can be added in a single statement + */ + public TransitionCriteriaChain add(TransitionCriteria criteria) { + this.criteriaChain.add(criteria); + return this; + } + + public boolean test(RequestContext context) { + for (TransitionCriteria criteria : criteriaChain) { + if (!criteria.test(context)) { + return false; + } + } + return true; + } + + public String toString() { + return new ToStringCreator(this).append("criteriaChain", criteriaChain).toString(); + } + + // static helpers + + /** + * Create a transition criteria chain chaining given list of actions. + * @param actions the actions (and their execution properties) to chain together + */ + public static TransitionCriteria criteriaChainFor(Action... actions) { + if (actions == null || actions.length == 0) { + return WildcardTransitionCriteria.INSTANCE; + } + TransitionCriteriaChain chain = new TransitionCriteriaChain(); + for (Action action : actions) { + chain.add(new ActionTransitionCriteria(action)); + } + return chain; + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/TransitionExecutingFlowExecutionExceptionHandler.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/TransitionExecutingFlowExecutionExceptionHandler.java index 0232bad6..7ba5c259 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/support/TransitionExecutingFlowExecutionExceptionHandler.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/support/TransitionExecutingFlowExecutionExceptionHandler.java @@ -1,193 +1,193 @@ -/* - * Copyright 2004-2020 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 - * - * https://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.engine.support; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.webflow.engine.ActionList; -import org.springframework.webflow.engine.FlowExecutionExceptionHandler; -import org.springframework.webflow.engine.RequestControlContext; -import org.springframework.webflow.engine.TargetStateResolver; -import org.springframework.webflow.engine.Transition; -import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.execution.RequestContext; - -/** - * A flow execution exception handler that maps the occurrence of a specific type of exception to a transition to a new - * {@link org.springframework.webflow.engine.State}. - *

- * The handled {@link FlowExecutionException} will be exposed in flash scope as - * {@link #FLOW_EXECUTION_EXCEPTION_ATTRIBUTE}. The underlying root cause of that exception will be exposed in flash - * scope as {@link #ROOT_CAUSE_EXCEPTION_ATTRIBUTE}. - * - * @author Keith Donald - */ -public class TransitionExecutingFlowExecutionExceptionHandler implements FlowExecutionExceptionHandler { - - private static final Log logger = LogFactory.getLog(TransitionExecutingFlowExecutionExceptionHandler.class); - - /** - * The name of the attribute to expose a handled exception under in flash scope ("flowExecutionException"). - */ - public static final String FLOW_EXECUTION_EXCEPTION_ATTRIBUTE = "flowExecutionException"; - - /** - * The name of the attribute to expose a root cause of a handled exception under in flash scope - * ("rootCauseException"). - */ - public static final String ROOT_CAUSE_EXCEPTION_ATTRIBUTE = "rootCauseException"; - - /** - * The exceptionType to targetStateResolver map. - */ - private Map, TargetStateResolver> exceptionTargetStateMappings = new HashMap<>(); - - /** - * The list of actions to execute when this handler handles an exception. - */ - private ActionList actionList = new ActionList(); - - /** - * Adds an exception-to-target state mapping to this handler. - * @param exceptionClass the type of exception to map - * @param targetStateId the id of the state to transition to if the specified type of exception is handled - * @return this handler, to allow for adding multiple mappings in a single statement - */ - public TransitionExecutingFlowExecutionExceptionHandler add(Class exceptionClass, - String targetStateId) { - return add(exceptionClass, new DefaultTargetStateResolver(targetStateId)); - } - - /** - * Adds a exception-to-target state resolver mapping to this handler. - * @param exceptionClass the type of exception to map - * @param targetStateResolver the resolver to calculate the state to transition to if the specified type of - * exception is handled - * @return this handler, to allow for adding multiple mappings in a single statement - */ - public TransitionExecutingFlowExecutionExceptionHandler add(Class exceptionClass, - TargetStateResolver targetStateResolver) { - Assert.notNull(exceptionClass, "The exception class is required"); - Assert.notNull(targetStateResolver, "The target state resolver is required"); - exceptionTargetStateMappings.put(exceptionClass, targetStateResolver); - return this; - } - - /** - * Returns the list of actions to execute when this handler handles an exception. The returned list is mutable. - */ - public ActionList getActionList() { - return actionList; - } - - public boolean canHandle(FlowExecutionException e) { - return getTargetStateResolver(e) != null; - } - - public void handle(FlowExecutionException exception, RequestControlContext context) { - if (logger.isDebugEnabled()) { - logger.debug("Handling flow execution exception " + exception, exception); - } - exposeException(context, exception, findRootCause(exception)); - actionList.execute(context); - context.execute(new Transition(getTargetStateResolver(exception))); - } - - // helpers - - /** - * Exposes the given flow exception and root cause in flash scope to make them available for response rendering. - * Subclasses can override this if they want to expose the exceptions in a different way or do special processing - * before the exceptions are exposed. - * @param context the request control context - * @param exception the exception being handled - * @param rootCause root cause of the exception being handled (could be null) - */ - protected void exposeException(RequestContext context, FlowExecutionException exception, Throwable rootCause) { - // note that all Throwables are Serializable so putting them in flash - // scope should not be a problem - context.getFlashScope().put(FLOW_EXECUTION_EXCEPTION_ATTRIBUTE, exception); - if (logger.isDebugEnabled()) { - logger.debug("Exposing flow execution exception root cause " + rootCause + " under attribute '" - + ROOT_CAUSE_EXCEPTION_ATTRIBUTE + "'"); - } - context.getFlashScope().put(ROOT_CAUSE_EXCEPTION_ATTRIBUTE, rootCause); - } - - /** - * Find the mapped target state resolver for given exception. Returns null if no mapping can be found - * for given exception. Will try all exceptions in the exception cause chain. - */ - protected TargetStateResolver getTargetStateResolver(Throwable e) { - TargetStateResolver targetStateResolver; - if (isRootCause(e)) { - return findTargetStateResolver(e.getClass()); - } else { - targetStateResolver = exceptionTargetStateMappings.get(e.getClass()); - if (targetStateResolver != null) { - return targetStateResolver; - } else { - return getTargetStateResolver(e.getCause()); - } - } - } - - /** - * Check if given exception is the root of the exception cause chain. For use with JDK 1.4 or later. - */ - private boolean isRootCause(Throwable t) { - return t.getCause() == null; - } - - /** - * Try to find a mapped target state resolver for given exception type. Will also try to lookup using the class - * hierarchy of given exception type. - * @param exceptionType the exception type to lookup - * @return the target state id or null if not found - */ - private TargetStateResolver findTargetStateResolver(Class exceptionType) { - Class type = exceptionType; - while (type != null && type != Object.class) { - if (exceptionTargetStateMappings.containsKey(type)) { - return exceptionTargetStateMappings.get(type); - } else { - type = type.getSuperclass(); - } - } - return null; - } - - /** - * Find the root cause of given throwable. For use on JDK 1.4 or later. - */ - private Throwable findRootCause(Throwable e) { - Throwable cause = e.getCause(); - if (cause == null) { - return e; - } else { - return findRootCause(cause); - } - } - - public String toString() { - return new ToStringCreator(this).append("exceptionHandlingMappings", exceptionTargetStateMappings).toString(); - } -} +/* + * Copyright 2004-2020 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 + * + * https://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.engine.support; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.webflow.engine.ActionList; +import org.springframework.webflow.engine.FlowExecutionExceptionHandler; +import org.springframework.webflow.engine.RequestControlContext; +import org.springframework.webflow.engine.TargetStateResolver; +import org.springframework.webflow.engine.Transition; +import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.execution.RequestContext; + +/** + * A flow execution exception handler that maps the occurrence of a specific type of exception to a transition to a new + * {@link org.springframework.webflow.engine.State}. + *

+ * The handled {@link FlowExecutionException} will be exposed in flash scope as + * {@link #FLOW_EXECUTION_EXCEPTION_ATTRIBUTE}. The underlying root cause of that exception will be exposed in flash + * scope as {@link #ROOT_CAUSE_EXCEPTION_ATTRIBUTE}. + * + * @author Keith Donald + */ +public class TransitionExecutingFlowExecutionExceptionHandler implements FlowExecutionExceptionHandler { + + private static final Log logger = LogFactory.getLog(TransitionExecutingFlowExecutionExceptionHandler.class); + + /** + * The name of the attribute to expose a handled exception under in flash scope ("flowExecutionException"). + */ + public static final String FLOW_EXECUTION_EXCEPTION_ATTRIBUTE = "flowExecutionException"; + + /** + * The name of the attribute to expose a root cause of a handled exception under in flash scope + * ("rootCauseException"). + */ + public static final String ROOT_CAUSE_EXCEPTION_ATTRIBUTE = "rootCauseException"; + + /** + * The exceptionType to targetStateResolver map. + */ + private Map, TargetStateResolver> exceptionTargetStateMappings = new HashMap<>(); + + /** + * The list of actions to execute when this handler handles an exception. + */ + private ActionList actionList = new ActionList(); + + /** + * Adds an exception-to-target state mapping to this handler. + * @param exceptionClass the type of exception to map + * @param targetStateId the id of the state to transition to if the specified type of exception is handled + * @return this handler, to allow for adding multiple mappings in a single statement + */ + public TransitionExecutingFlowExecutionExceptionHandler add(Class exceptionClass, + String targetStateId) { + return add(exceptionClass, new DefaultTargetStateResolver(targetStateId)); + } + + /** + * Adds a exception-to-target state resolver mapping to this handler. + * @param exceptionClass the type of exception to map + * @param targetStateResolver the resolver to calculate the state to transition to if the specified type of + * exception is handled + * @return this handler, to allow for adding multiple mappings in a single statement + */ + public TransitionExecutingFlowExecutionExceptionHandler add(Class exceptionClass, + TargetStateResolver targetStateResolver) { + Assert.notNull(exceptionClass, "The exception class is required"); + Assert.notNull(targetStateResolver, "The target state resolver is required"); + exceptionTargetStateMappings.put(exceptionClass, targetStateResolver); + return this; + } + + /** + * Returns the list of actions to execute when this handler handles an exception. The returned list is mutable. + */ + public ActionList getActionList() { + return actionList; + } + + public boolean canHandle(FlowExecutionException e) { + return getTargetStateResolver(e) != null; + } + + public void handle(FlowExecutionException exception, RequestControlContext context) { + if (logger.isDebugEnabled()) { + logger.debug("Handling flow execution exception " + exception, exception); + } + exposeException(context, exception, findRootCause(exception)); + actionList.execute(context); + context.execute(new Transition(getTargetStateResolver(exception))); + } + + // helpers + + /** + * Exposes the given flow exception and root cause in flash scope to make them available for response rendering. + * Subclasses can override this if they want to expose the exceptions in a different way or do special processing + * before the exceptions are exposed. + * @param context the request control context + * @param exception the exception being handled + * @param rootCause root cause of the exception being handled (could be null) + */ + protected void exposeException(RequestContext context, FlowExecutionException exception, Throwable rootCause) { + // note that all Throwables are Serializable so putting them in flash + // scope should not be a problem + context.getFlashScope().put(FLOW_EXECUTION_EXCEPTION_ATTRIBUTE, exception); + if (logger.isDebugEnabled()) { + logger.debug("Exposing flow execution exception root cause " + rootCause + " under attribute '" + + ROOT_CAUSE_EXCEPTION_ATTRIBUTE + "'"); + } + context.getFlashScope().put(ROOT_CAUSE_EXCEPTION_ATTRIBUTE, rootCause); + } + + /** + * Find the mapped target state resolver for given exception. Returns null if no mapping can be found + * for given exception. Will try all exceptions in the exception cause chain. + */ + protected TargetStateResolver getTargetStateResolver(Throwable e) { + TargetStateResolver targetStateResolver; + if (isRootCause(e)) { + return findTargetStateResolver(e.getClass()); + } else { + targetStateResolver = exceptionTargetStateMappings.get(e.getClass()); + if (targetStateResolver != null) { + return targetStateResolver; + } else { + return getTargetStateResolver(e.getCause()); + } + } + } + + /** + * Check if given exception is the root of the exception cause chain. For use with JDK 1.4 or later. + */ + private boolean isRootCause(Throwable t) { + return t.getCause() == null; + } + + /** + * Try to find a mapped target state resolver for given exception type. Will also try to lookup using the class + * hierarchy of given exception type. + * @param exceptionType the exception type to lookup + * @return the target state id or null if not found + */ + private TargetStateResolver findTargetStateResolver(Class exceptionType) { + Class type = exceptionType; + while (type != null && type != Object.class) { + if (exceptionTargetStateMappings.containsKey(type)) { + return exceptionTargetStateMappings.get(type); + } else { + type = type.getSuperclass(); + } + } + return null; + } + + /** + * Find the root cause of given throwable. For use on JDK 1.4 or later. + */ + private Throwable findRootCause(Throwable e) { + Throwable cause = e.getCause(); + if (cause == null) { + return e; + } else { + return findRootCause(cause); + } + } + + public String toString() { + return new ToStringCreator(this).append("exceptionHandlingMappings", exceptionTargetStateMappings).toString(); + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/Action.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/Action.java index 16ec58ec..7173c073 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/Action.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/Action.java @@ -1,101 +1,101 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -/** - * A command that executes a behavior and returns a logical execution result a calling flow execution can respond to. - *

- * Actions typically delegate down to the application (or service) layer to perform business operations. They often - * retrieve data to support response rendering. They act as a bridge between a SWF web-tier and your middle-tier - * business logic layer. - *

- * When an action completes execution it signals a result event describing the outcome of that execution (for example, - * "success", "error", "yes", "no", "tryAgain", etc). In addition to providing a logical outcome the flow can respond - * to, a result event may have payload associated with it, for example a "success" return value or an "error" error - * code. The result event is typically used as grounds for a state transition out of the current state of the calling - * Flow. - *

- * Action implementations are often application-scoped singletons instantiated and managed by a web-tier Spring - * application context to take advantage of Spring's externalized configuration and dependency injection capabilities - * (which is a form of Inversion of Control [IoC]). Actions may also be stateful prototypes, storing conversational - * state as instance variables. Action instance definitions may also be locally scoped to a specific flow definition - * (see use of the "import" element of the root XML flow definition element.) - *

- * Note: Actions are directly instantiatable for use in a standalone test environment and can be parameterized with - * mocks or stubs, as they are simple POJOs. Action proxies may also be generated at runtime for delegating to POJO - * business operations that have no dependency on the Spring Web Flow API. - *

- * Note: if an Action is a singleton managed in application scope, take care not to store and/or modify caller-specific - * state in a unsafe manner. The Action {@link #execute(RequestContext)} method runs in an independently executing - * thread on each invocation so make sure you deal only with local data or internal, thread-safe services. - *

- * Note: an Action is not a controller like a Spring MVC controller or a Struts action is a controller. Flow actions are - * commands. Such commands do not select views, they execute arbitrary behavioral logic and then return an - * logical execution result. The flow that invokes an Action is responsible for responding to the execution result to - * decide what to do next. In Spring Web Flow, the flow is the controller. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface Action { - - /** - * Execute this action. Action execution will occur in the context of a request associated with an active flow - * execution. - *

- * Action invocation is typically triggered in a production environment by a state within a flow carrying out the - * execution of a flow definition. The result of action execution, a logical outcome event, can be used as grounds - * for a transition out of the calling state. - *

- * Note: The {@link RequestContext} argument to this method provides access to data about the active flow execution - * in the context of the currently executing thread. Among other things, this allows this action to access - * {@link RequestContext#getRequestScope() data} set by other actions, as well as set its own attributes it wishes - * to expose in a given scope. - *

- * Some notes about actions and their usage of the attribute scope types: - *

    - *
  • Attributes set in {@link RequestContext#getRequestScope() request scope} exist for the life of the currently - * executing request only. - *
  • Attributes set in {@link RequestContext#getFlashScope() flash scope} exist until after view rendering is - * completed. That time includes the current request plus any redirect required for the view render to complete. - *
  • Attributes set in {@link RequestContext#getFlowScope() flow scope} exist for the life of the flow session and - * will be cleaned up automatically when the flow session ends. - *
  • Attributes set in {@link RequestContext#getConversationScope() conversation scope} exist for the life of the - * entire flow execution representing a single logical "conversation" with a user. - *
- *

- * All attributes present in any scope are typically exposed in a model for access by a view when an "interactive" - * state type such as a view state is entered. - *

- * Note: flow scope should generally not be used as a general purpose cache, but rather as a context for data needed - * locally by other states of the flow this action participates in. For example, it would be inappropriate to stuff - * large collections of objects (like those returned to support a search results view) into flow scope. Instead, put - * such result collections in request scope, and ensure you execute this action again each time you wish to view - * those results. 2nd level caches managed outside of SWF are more general cache solutions. - *

- * Note: as flow scoped attributes are eligible for serialization they should be Serializable. - * - * @param context the action execution context, for accessing and setting data in a {@link ScopeType scope type}, as - * well as obtaining other flow contextual information (e.g. request context attributes and flow execution context - * information) - * @return a logical result outcome, used as grounds for a transition in the calling flow (e.g. "success", "error", - * "yes", "no", * ...) - * @throws Exception a exception occurred during action execution, either checked or unchecked; note, any - * recoverable exceptions should be caught within this method and an appropriate result outcome returned - * or be handled by the current state of the calling flow execution. - */ - Event execute(RequestContext context) throws Exception; -} +/* + * Copyright 2004-2012 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 + * + * https://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; + +/** + * A command that executes a behavior and returns a logical execution result a calling flow execution can respond to. + *

+ * Actions typically delegate down to the application (or service) layer to perform business operations. They often + * retrieve data to support response rendering. They act as a bridge between a SWF web-tier and your middle-tier + * business logic layer. + *

+ * When an action completes execution it signals a result event describing the outcome of that execution (for example, + * "success", "error", "yes", "no", "tryAgain", etc). In addition to providing a logical outcome the flow can respond + * to, a result event may have payload associated with it, for example a "success" return value or an "error" error + * code. The result event is typically used as grounds for a state transition out of the current state of the calling + * Flow. + *

+ * Action implementations are often application-scoped singletons instantiated and managed by a web-tier Spring + * application context to take advantage of Spring's externalized configuration and dependency injection capabilities + * (which is a form of Inversion of Control [IoC]). Actions may also be stateful prototypes, storing conversational + * state as instance variables. Action instance definitions may also be locally scoped to a specific flow definition + * (see use of the "import" element of the root XML flow definition element.) + *

+ * Note: Actions are directly instantiatable for use in a standalone test environment and can be parameterized with + * mocks or stubs, as they are simple POJOs. Action proxies may also be generated at runtime for delegating to POJO + * business operations that have no dependency on the Spring Web Flow API. + *

+ * Note: if an Action is a singleton managed in application scope, take care not to store and/or modify caller-specific + * state in a unsafe manner. The Action {@link #execute(RequestContext)} method runs in an independently executing + * thread on each invocation so make sure you deal only with local data or internal, thread-safe services. + *

+ * Note: an Action is not a controller like a Spring MVC controller or a Struts action is a controller. Flow actions are + * commands. Such commands do not select views, they execute arbitrary behavioral logic and then return an + * logical execution result. The flow that invokes an Action is responsible for responding to the execution result to + * decide what to do next. In Spring Web Flow, the flow is the controller. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface Action { + + /** + * Execute this action. Action execution will occur in the context of a request associated with an active flow + * execution. + *

+ * Action invocation is typically triggered in a production environment by a state within a flow carrying out the + * execution of a flow definition. The result of action execution, a logical outcome event, can be used as grounds + * for a transition out of the calling state. + *

+ * Note: The {@link RequestContext} argument to this method provides access to data about the active flow execution + * in the context of the currently executing thread. Among other things, this allows this action to access + * {@link RequestContext#getRequestScope() data} set by other actions, as well as set its own attributes it wishes + * to expose in a given scope. + *

+ * Some notes about actions and their usage of the attribute scope types: + *

    + *
  • Attributes set in {@link RequestContext#getRequestScope() request scope} exist for the life of the currently + * executing request only. + *
  • Attributes set in {@link RequestContext#getFlashScope() flash scope} exist until after view rendering is + * completed. That time includes the current request plus any redirect required for the view render to complete. + *
  • Attributes set in {@link RequestContext#getFlowScope() flow scope} exist for the life of the flow session and + * will be cleaned up automatically when the flow session ends. + *
  • Attributes set in {@link RequestContext#getConversationScope() conversation scope} exist for the life of the + * entire flow execution representing a single logical "conversation" with a user. + *
+ *

+ * All attributes present in any scope are typically exposed in a model for access by a view when an "interactive" + * state type such as a view state is entered. + *

+ * Note: flow scope should generally not be used as a general purpose cache, but rather as a context for data needed + * locally by other states of the flow this action participates in. For example, it would be inappropriate to stuff + * large collections of objects (like those returned to support a search results view) into flow scope. Instead, put + * such result collections in request scope, and ensure you execute this action again each time you wish to view + * those results. 2nd level caches managed outside of SWF are more general cache solutions. + *

+ * Note: as flow scoped attributes are eligible for serialization they should be Serializable. + * + * @param context the action execution context, for accessing and setting data in a {@link ScopeType scope type}, as + * well as obtaining other flow contextual information (e.g. request context attributes and flow execution context + * information) + * @return a logical result outcome, used as grounds for a transition in the calling flow (e.g. "success", "error", + * "yes", "no", * ...) + * @throws Exception a exception occurred during action execution, either checked or unchecked; note, any + * recoverable exceptions should be caught within this method and an appropriate result outcome returned + * or be handled by the current state of the calling flow execution. + */ + Event execute(RequestContext context) throws Exception; +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/ActionExecutionException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/ActionExecutionException.java index 535f10ba..3d33c731 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/ActionExecutionException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/ActionExecutionException.java @@ -1,59 +1,59 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -import org.springframework.webflow.core.collection.AttributeMap; - -/** - * Thrown if an unhandled exception occurs when an action is executed. Typically wraps another exception noting the root - * cause failure. The root cause may be checked or unchecked. - * - * @see org.springframework.webflow.execution.Action - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class ActionExecutionException extends FlowExecutionException { - - /** - * Create a new action execution exception. - * @param flowId the current flow - * @param stateId the current state (may be null) - * @param action the action that generated an unrecoverable exception - * @param executionAttributes action execution properties that may have contributed to this failure - * @param cause the underlying cause - */ - public ActionExecutionException(String flowId, String stateId, Action action, - AttributeMap executionAttributes, Throwable cause) { - super(flowId, stateId, "Exception thrown executing " + action + " in state '" + stateId + "' of flow '" - + flowId + "' -- action execution attributes were '" + executionAttributes + "'", cause); - } - - /** - * Create a new action execution exception. - * @param flowId the current flow - * @param stateId the current state (may be null) - * @param action the action that generated an unrecoverable exception - * @param executionAttributes action execution properties that may have contributed to this failure - * @param message a descriptive message - * @param cause the underlying cause - */ - public ActionExecutionException(String flowId, String stateId, Action action, - AttributeMap executionAttributes, String message, Throwable cause) { - super(flowId, stateId, message, cause); - } - +/* + * Copyright 2004-2012 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 + * + * https://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; + +import org.springframework.webflow.core.collection.AttributeMap; + +/** + * Thrown if an unhandled exception occurs when an action is executed. Typically wraps another exception noting the root + * cause failure. The root cause may be checked or unchecked. + * + * @see org.springframework.webflow.execution.Action + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class ActionExecutionException extends FlowExecutionException { + + /** + * Create a new action execution exception. + * @param flowId the current flow + * @param stateId the current state (may be null) + * @param action the action that generated an unrecoverable exception + * @param executionAttributes action execution properties that may have contributed to this failure + * @param cause the underlying cause + */ + public ActionExecutionException(String flowId, String stateId, Action action, + AttributeMap executionAttributes, Throwable cause) { + super(flowId, stateId, "Exception thrown executing " + action + " in state '" + stateId + "' of flow '" + + flowId + "' -- action execution attributes were '" + executionAttributes + "'", cause); + } + + /** + * Create a new action execution exception. + * @param flowId the current flow + * @param stateId the current state (may be null) + * @param action the action that generated an unrecoverable exception + * @param executionAttributes action execution properties that may have contributed to this failure + * @param message a descriptive message + * @param cause the underlying cause + */ + public ActionExecutionException(String flowId, String stateId, Action action, + AttributeMap executionAttributes, String message, Throwable cause) { + super(flowId, stateId, message, cause); + } + } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/ActionExecutor.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/ActionExecutor.java index 39fae204..a7ec9151 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/ActionExecutor.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/ActionExecutor.java @@ -1,73 +1,73 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A simple static helper that performs action execution that encapsulates common logging and exception handling logic. - * This is an internal helper class that is not normally used by application code. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class ActionExecutor { - - private static final Log logger = LogFactory.getLog(ActionExecutor.class); - - /** - * Private constructor to avoid instantiation. - */ - private ActionExecutor() { - } - - /** - * Execute the given action. - * @param action the action to execute - * @param context the flow execution request context - * @return result of action execution - * @throws ActionExecutionException if the action threw an exception while executing, the orginal exception is - * available as the cause if this exception - */ - public static Event execute(Action action, RequestContext context) throws ActionExecutionException { - try { - if (logger.isDebugEnabled()) { - logger.debug("Executing " + getTargetAction(action)); - } - Event event = action.execute(context); - if (logger.isDebugEnabled()) { - logger.debug("Finished executing " + getTargetAction(action) + "; result = " + event); - } - return event; - } catch (ActionExecutionException e) { - throw e; - } catch (Exception e) { - // wrap the exception as an ActionExecutionException - throw new ActionExecutionException(context.getActiveFlow().getId(), - context.getCurrentState() != null ? context.getCurrentState().getId() : null, action, - context.getAttributes(), e); - } - } - - private static Action getTargetAction(Action action) { - if (action instanceof AnnotatedAction) { - return getTargetAction(((AnnotatedAction) action).getTargetAction()); - } else { - return action; - } - } +/* + * Copyright 2004-2012 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 + * + * https://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; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A simple static helper that performs action execution that encapsulates common logging and exception handling logic. + * This is an internal helper class that is not normally used by application code. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class ActionExecutor { + + private static final Log logger = LogFactory.getLog(ActionExecutor.class); + + /** + * Private constructor to avoid instantiation. + */ + private ActionExecutor() { + } + + /** + * Execute the given action. + * @param action the action to execute + * @param context the flow execution request context + * @return result of action execution + * @throws ActionExecutionException if the action threw an exception while executing, the orginal exception is + * available as the cause if this exception + */ + public static Event execute(Action action, RequestContext context) throws ActionExecutionException { + try { + if (logger.isDebugEnabled()) { + logger.debug("Executing " + getTargetAction(action)); + } + Event event = action.execute(context); + if (logger.isDebugEnabled()) { + logger.debug("Finished executing " + getTargetAction(action) + "; result = " + event); + } + return event; + } catch (ActionExecutionException e) { + throw e; + } catch (Exception e) { + // wrap the exception as an ActionExecutionException + throw new ActionExecutionException(context.getActiveFlow().getId(), + context.getCurrentState() != null ? context.getCurrentState().getId() : null, action, + context.getAttributes(), e); + } + } + + private static Action getTargetAction(Action action) { + if (action instanceof AnnotatedAction) { + return getTargetAction(((AnnotatedAction) action).getTargetAction()); + } else { + return action; + } + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/AnnotatedAction.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/AnnotatedAction.java index aec8ab8d..26861c03 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/AnnotatedAction.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/AnnotatedAction.java @@ -1,182 +1,182 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; -import org.springframework.webflow.core.AnnotatedObject; - -/** - * An action proxy/decorator that stores arbitrary properties about a target Action implementation for use - * within a specific Action execution context, for example an ActionState definition, a - * TransitionCriteria definition, or in a test environment. - *

- * An annotated action is an action that wraps another action (referred to as the target action), setting up the - * target action's execution attributes before invoking {@link Action#execute}. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class AnnotatedAction extends AnnotatedObject implements Action { - - private static final Log logger = LogFactory.getLog(AnnotatedAction.class); - - // well known attributes - - /** - * The action name attribute ("name"). - *

- * The name attribute is often used as a qualifier for an action's result event, and is typically used to allow the - * flow to respond to a specific action's outcome within a larger action execution chain. - */ - public static final String NAME_ATTRIBUTE = "name"; - - /** - * The action execution method attribute ("method"). - *

- * The method property is a hint about what method should be invoked. - */ - public static final String METHOD_ATTRIBUTE = "method"; - - /** - * The target action to execute. - */ - private Action targetAction; - - /** - * Creates a new annotated action object for the specified action. No contextual properties are provided. - * @param targetAction the action - */ - public AnnotatedAction(Action targetAction) { - setTargetAction(targetAction); - } - - /** - * Returns the wrapped target action. - * @return the action - */ - public Action getTargetAction() { - return targetAction; - } - - /** - * Set the target action wrapped by this decorator. - */ - public void setTargetAction(Action targetAction) { - Assert.notNull(targetAction, "The targetAction to annotate is required"); - this.targetAction = targetAction; - } - - /** - * Returns the name of a named action, or null if the action is unnamed. Used when mapping action - * result events to transitions. - * @see #isNamed() - * @see #postProcessResult(Event) - */ - public String getName() { - return getAttributes().getString(NAME_ATTRIBUTE); - } - - /** - * Sets the name of a named action. This is optional and can be null. - * @param name the action name - */ - public void setName(String name) { - getAttributes().put(NAME_ATTRIBUTE, name); - } - - /** - * Returns whether or not the wrapped target action is a named action. - * @see #getName() - * @see #setName(String) - */ - public boolean isNamed() { - return StringUtils.hasText(getName()); - } - - /** - * Returns the name of the action method to invoke when the target action is executed. - */ - public String getMethod() { - return getAttributes().getString(METHOD_ATTRIBUTE); - } - - /** - * Sets the name of the action method to invoke when the target action is executed. - * @param method the action method name - */ - public void setMethod(String method) { - getAttributes().put(METHOD_ATTRIBUTE, method); - } - - /** - * Set an attribute on this annotated object. - * @param attributeName the name of the attribute to set - * @param attributeValue the value of the attribute - * @return this object, to support call chaining - */ - public AnnotatedAction putAttribute(String attributeName, Object attributeValue) { - getAttributes().put(attributeName, attributeValue); - return this; - } - - public Event execute(RequestContext context) throws Exception { - try { - if (logger.isDebugEnabled()) { - logger.debug("Putting action execution attributes " + getAttributes()); - } - context.getAttributes().putAll(getAttributes()); - Event result = getTargetAction().execute(context); - return postProcessResult(result); - } finally { - if (logger.isDebugEnabled()) { - logger.debug("Clearing action execution attributes " + getAttributes()); - } - context.getAttributes().removeAll(getAttributes()); - } - } - - /** - * Get the event id to be used as grounds for a transition in the containing state, based on given result returned - * from action execution. - *

- * If the wrapped action is named, the name will be used as a qualifier for the event (e.g. "myAction.success"). - * @param resultEvent the action result event - */ - protected Event postProcessResult(Event resultEvent) { - if (resultEvent == null) { - return null; - } - if (isNamed()) { - // qualify result event id with action name for a named action - String qualifiedId = getName() + "." + resultEvent.getId(); - if (logger.isDebugEnabled()) { - logger.debug("Qualifying action result '" + resultEvent.getId() + "'; qualified result = '" - + qualifiedId + "'"); - } - resultEvent = new Event(resultEvent.getSource(), qualifiedId, resultEvent.getAttributes()); - } - return resultEvent; - } - - public String toString() { - return new ToStringCreator(this).append("targetAction", getTargetAction()) - .append("attributes", getAttributes()).toString(); - } +/* + * Copyright 2004-2012 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 + * + * https://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; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.webflow.core.AnnotatedObject; + +/** + * An action proxy/decorator that stores arbitrary properties about a target Action implementation for use + * within a specific Action execution context, for example an ActionState definition, a + * TransitionCriteria definition, or in a test environment. + *

+ * An annotated action is an action that wraps another action (referred to as the target action), setting up the + * target action's execution attributes before invoking {@link Action#execute}. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class AnnotatedAction extends AnnotatedObject implements Action { + + private static final Log logger = LogFactory.getLog(AnnotatedAction.class); + + // well known attributes + + /** + * The action name attribute ("name"). + *

+ * The name attribute is often used as a qualifier for an action's result event, and is typically used to allow the + * flow to respond to a specific action's outcome within a larger action execution chain. + */ + public static final String NAME_ATTRIBUTE = "name"; + + /** + * The action execution method attribute ("method"). + *

+ * The method property is a hint about what method should be invoked. + */ + public static final String METHOD_ATTRIBUTE = "method"; + + /** + * The target action to execute. + */ + private Action targetAction; + + /** + * Creates a new annotated action object for the specified action. No contextual properties are provided. + * @param targetAction the action + */ + public AnnotatedAction(Action targetAction) { + setTargetAction(targetAction); + } + + /** + * Returns the wrapped target action. + * @return the action + */ + public Action getTargetAction() { + return targetAction; + } + + /** + * Set the target action wrapped by this decorator. + */ + public void setTargetAction(Action targetAction) { + Assert.notNull(targetAction, "The targetAction to annotate is required"); + this.targetAction = targetAction; + } + + /** + * Returns the name of a named action, or null if the action is unnamed. Used when mapping action + * result events to transitions. + * @see #isNamed() + * @see #postProcessResult(Event) + */ + public String getName() { + return getAttributes().getString(NAME_ATTRIBUTE); + } + + /** + * Sets the name of a named action. This is optional and can be null. + * @param name the action name + */ + public void setName(String name) { + getAttributes().put(NAME_ATTRIBUTE, name); + } + + /** + * Returns whether or not the wrapped target action is a named action. + * @see #getName() + * @see #setName(String) + */ + public boolean isNamed() { + return StringUtils.hasText(getName()); + } + + /** + * Returns the name of the action method to invoke when the target action is executed. + */ + public String getMethod() { + return getAttributes().getString(METHOD_ATTRIBUTE); + } + + /** + * Sets the name of the action method to invoke when the target action is executed. + * @param method the action method name + */ + public void setMethod(String method) { + getAttributes().put(METHOD_ATTRIBUTE, method); + } + + /** + * Set an attribute on this annotated object. + * @param attributeName the name of the attribute to set + * @param attributeValue the value of the attribute + * @return this object, to support call chaining + */ + public AnnotatedAction putAttribute(String attributeName, Object attributeValue) { + getAttributes().put(attributeName, attributeValue); + return this; + } + + public Event execute(RequestContext context) throws Exception { + try { + if (logger.isDebugEnabled()) { + logger.debug("Putting action execution attributes " + getAttributes()); + } + context.getAttributes().putAll(getAttributes()); + Event result = getTargetAction().execute(context); + return postProcessResult(result); + } finally { + if (logger.isDebugEnabled()) { + logger.debug("Clearing action execution attributes " + getAttributes()); + } + context.getAttributes().removeAll(getAttributes()); + } + } + + /** + * Get the event id to be used as grounds for a transition in the containing state, based on given result returned + * from action execution. + *

+ * If the wrapped action is named, the name will be used as a qualifier for the event (e.g. "myAction.success"). + * @param resultEvent the action result event + */ + protected Event postProcessResult(Event resultEvent) { + if (resultEvent == null) { + return null; + } + if (isNamed()) { + // qualify result event id with action name for a named action + String qualifiedId = getName() + "." + resultEvent.getId(); + if (logger.isDebugEnabled()) { + logger.debug("Qualifying action result '" + resultEvent.getId() + "'; qualified result = '" + + qualifiedId + "'"); + } + resultEvent = new Event(resultEvent.getSource(), qualifiedId, resultEvent.getAttributes()); + } + return resultEvent; + } + + public String toString() { + return new ToStringCreator(this).append("targetAction", getTargetAction()) + .append("attributes", getAttributes()).toString(); + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/EnterStateVetoException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/EnterStateVetoException.java index 8c5c34ae..afa8502e 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/EnterStateVetoException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/EnterStateVetoException.java @@ -1,87 +1,87 @@ -/* - * 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 - * - * https://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; - -import org.springframework.webflow.definition.StateDefinition; - -/** - * Exception thrown to veto the entering of a state of a flow. Typically thrown by {@link FlowExecutionListener} objects - * that apply security or other runtime constraint checks to flow executions. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class EnterStateVetoException extends FlowExecutionException { - - /** - * The state whose entering was vetoed. - */ - private String vetoedStateId; - - /** - * Create a new enter state veto exception. - * @param flowId the active flow - * @param sourceStateId the current state when the veto operation occured - * @param vetoedStateId the state for which entering is vetoed - * @param message a descriptive message - */ - public EnterStateVetoException(String flowId, String sourceStateId, String vetoedStateId, String message) { - super(flowId, sourceStateId, message); - this.vetoedStateId = vetoedStateId; - } - - /** - * Create a new enter state veto exception. - * @param flowId the active flow - * @param sourceStateId the current state when the veto operation occured - * @param vetoedStateId the state for which entering is vetoed - * @param message a descriptive message - * @param cause the underlying cause - */ - public EnterStateVetoException(String flowId, String sourceStateId, String vetoedStateId, String message, - Throwable cause) { - super(flowId, sourceStateId, message, cause); - this.vetoedStateId = vetoedStateId; - } - - /** - * Create a new enter state veto exception. - * @param context the flow execution request context - * @param vetoedState the state for which entering is vetoed - * @param message a descriptive message - */ - public EnterStateVetoException(RequestContext context, StateDefinition vetoedState, String message) { - this(context.getActiveFlow().getId(), context.getCurrentState().getId(), vetoedState.getId(), message); - } - - /** - * Create a new enter state veto exception. - * @param context the flow execution request context - * @param vetoedState the state for which entering is vetoed - * @param message a descriptive message - * @param cause the underlying cause - */ - public EnterStateVetoException(RequestContext context, StateDefinition vetoedState, String message, Throwable cause) { - this(context.getActiveFlow().getId(), context.getCurrentState().getId(), vetoedState.getId(), message, cause); - } - - /** - * Returns the state for which entering was vetoed. - */ - public String getVetoedStateId() { - return vetoedStateId; - } +/* + * 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 + * + * https://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; + +import org.springframework.webflow.definition.StateDefinition; + +/** + * Exception thrown to veto the entering of a state of a flow. Typically thrown by {@link FlowExecutionListener} objects + * that apply security or other runtime constraint checks to flow executions. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class EnterStateVetoException extends FlowExecutionException { + + /** + * The state whose entering was vetoed. + */ + private String vetoedStateId; + + /** + * Create a new enter state veto exception. + * @param flowId the active flow + * @param sourceStateId the current state when the veto operation occured + * @param vetoedStateId the state for which entering is vetoed + * @param message a descriptive message + */ + public EnterStateVetoException(String flowId, String sourceStateId, String vetoedStateId, String message) { + super(flowId, sourceStateId, message); + this.vetoedStateId = vetoedStateId; + } + + /** + * Create a new enter state veto exception. + * @param flowId the active flow + * @param sourceStateId the current state when the veto operation occured + * @param vetoedStateId the state for which entering is vetoed + * @param message a descriptive message + * @param cause the underlying cause + */ + public EnterStateVetoException(String flowId, String sourceStateId, String vetoedStateId, String message, + Throwable cause) { + super(flowId, sourceStateId, message, cause); + this.vetoedStateId = vetoedStateId; + } + + /** + * Create a new enter state veto exception. + * @param context the flow execution request context + * @param vetoedState the state for which entering is vetoed + * @param message a descriptive message + */ + public EnterStateVetoException(RequestContext context, StateDefinition vetoedState, String message) { + this(context.getActiveFlow().getId(), context.getCurrentState().getId(), vetoedState.getId(), message); + } + + /** + * Create a new enter state veto exception. + * @param context the flow execution request context + * @param vetoedState the state for which entering is vetoed + * @param message a descriptive message + * @param cause the underlying cause + */ + public EnterStateVetoException(RequestContext context, StateDefinition vetoedState, String message, Throwable cause) { + this(context.getActiveFlow().getId(), context.getCurrentState().getId(), vetoedState.getId(), message, cause); + } + + /** + * Returns the state for which entering was vetoed. + */ + public String getVetoedStateId() { + return vetoedStateId; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/Event.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/Event.java index 7be12f64..c5fac282 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/Event.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/Event.java @@ -1,107 +1,107 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -import java.util.EventObject; - -import org.springframework.util.Assert; -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.core.collection.CollectionUtils; - -/** - * Signals the occurrence of something an active flow execution should respond to. Each event has a string id that - * provides a key for identifying what happened: e.g "coinInserted", or "pinDropped". Events may have attributes that - * provide arbitrary payload data, e.g. "coin.amount=25", or "pinDropSpeed=25ms". - *

- * As an example, a "submit" event might signal that a Submit button was pressed in a web browser. A "success" event - * might signal an action executed successfully. A "finish" event might signal a subflow ended normally. - *

- * Why is this not an interface? A specific design choice. An event is not a strategy that defines a generic type or - * role--it is essentially an immutable value object. It is expected that specializations of this base class be "Events" - * and not part of some other inheritance hierarchy. - * - * @author Keith Donald - * @author Erwin Vervaet - * @author Colin Sampaleanu - */ -public class Event extends EventObject { - - /** - * The event identifier. - */ - private final String id; - - /** - * The time the event occurred. - */ - private final long timestamp = System.currentTimeMillis(); - - /** - * Additional event attributes that form this event's payload. - */ - private final AttributeMap attributes; - - /** - * Create a new event with the specified id and no payload. - * @param source the source of the event (required) - * @param id the event identifier (required) - */ - public Event(Object source, String id) { - this(source, id, null); - } - - /** - * Create a new event with the specified id and payload attributes. - * @param source the source of the event (required) - * @param id the event identifier (required) - * @param attributes additional event attributes - */ - public Event(Object source, String id, AttributeMap attributes) { - super(source); - Assert.hasText(id, "The event id is required: please set this event's id to a non-blank string identifier"); - this.id = id; - this.attributes = attributes != null ? attributes : CollectionUtils.EMPTY_ATTRIBUTE_MAP; - } - - /** - * Returns the event identifier. - * @return the event id - */ - public String getId() { - return id; - } - - /** - * Returns the time at which the event occurred, represented as the number of milliseconds since January 1, 1970, - * 00:00:00 GMT. - * @return the timestamp - */ - public long getTimestamp() { - return timestamp; - } - - /** - * Returns an unmodifiable map storing the attributes of this event. Never returns null. - * @return the event attributes (payload) - */ - public AttributeMap getAttributes() { - return attributes; - } - - public String toString() { - return getId(); - } +/* + * Copyright 2004-2012 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 + * + * https://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; + +import java.util.EventObject; + +import org.springframework.util.Assert; +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.core.collection.CollectionUtils; + +/** + * Signals the occurrence of something an active flow execution should respond to. Each event has a string id that + * provides a key for identifying what happened: e.g "coinInserted", or "pinDropped". Events may have attributes that + * provide arbitrary payload data, e.g. "coin.amount=25", or "pinDropSpeed=25ms". + *

+ * As an example, a "submit" event might signal that a Submit button was pressed in a web browser. A "success" event + * might signal an action executed successfully. A "finish" event might signal a subflow ended normally. + *

+ * Why is this not an interface? A specific design choice. An event is not a strategy that defines a generic type or + * role--it is essentially an immutable value object. It is expected that specializations of this base class be "Events" + * and not part of some other inheritance hierarchy. + * + * @author Keith Donald + * @author Erwin Vervaet + * @author Colin Sampaleanu + */ +public class Event extends EventObject { + + /** + * The event identifier. + */ + private final String id; + + /** + * The time the event occurred. + */ + private final long timestamp = System.currentTimeMillis(); + + /** + * Additional event attributes that form this event's payload. + */ + private final AttributeMap attributes; + + /** + * Create a new event with the specified id and no payload. + * @param source the source of the event (required) + * @param id the event identifier (required) + */ + public Event(Object source, String id) { + this(source, id, null); + } + + /** + * Create a new event with the specified id and payload attributes. + * @param source the source of the event (required) + * @param id the event identifier (required) + * @param attributes additional event attributes + */ + public Event(Object source, String id, AttributeMap attributes) { + super(source); + Assert.hasText(id, "The event id is required: please set this event's id to a non-blank string identifier"); + this.id = id; + this.attributes = attributes != null ? attributes : CollectionUtils.EMPTY_ATTRIBUTE_MAP; + } + + /** + * Returns the event identifier. + * @return the event id + */ + public String getId() { + return id; + } + + /** + * Returns the time at which the event occurred, represented as the number of milliseconds since January 1, 1970, + * 00:00:00 GMT. + * @return the timestamp + */ + public long getTimestamp() { + return timestamp; + } + + /** + * Returns an unmodifiable map storing the attributes of this event. Never returns null. + * @return the event attributes (payload) + */ + public AttributeMap getAttributes() { + return attributes; + } + + public String toString() { + return getId(); + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecution.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecution.java index fa2999c8..e35967ab 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecution.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecution.java @@ -1,53 +1,53 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -import org.springframework.webflow.context.ExternalContext; -import org.springframework.webflow.core.collection.MutableAttributeMap; - -/** - * An execution of a flow definition. This is the central interface for manipulating a instance of a flow definition. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface FlowExecution extends FlowExecutionContext { - - /** - * Start this flow execution. This method should only be called once. - *

- * When this method returns, execution status is either "paused" or "ended". If ended, the flow execution cannot be - * used again. If "paused", the flow execution may be {@link #resume(ExternalContext) resumed}. - * @param input flow execution input - * @param context the external context representing the calling environment - * @throws FlowExecutionException if an exception was thrown within a state of the flow execution during request - * processing - */ - void start(MutableAttributeMap input, ExternalContext context) throws FlowExecutionException; - - /** - * Resume this flow execution. May be called when the flow execution is paused. - * - * When this method returns, execution status is either "paused" or "ended". If ended, the flow execution cannot be - * used again. If "paused", the flow execution may be resumed again. - * @param context the external context, representing the calling environment, where something happened this flow - * execution should respond to - * @throws FlowExecutionException if an exception was thrown within a state of the resumed flow execution during - * event processing - */ - void resume(ExternalContext context) throws FlowExecutionException; - -} +/* + * Copyright 2004-2012 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 + * + * https://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; + +import org.springframework.webflow.context.ExternalContext; +import org.springframework.webflow.core.collection.MutableAttributeMap; + +/** + * An execution of a flow definition. This is the central interface for manipulating a instance of a flow definition. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface FlowExecution extends FlowExecutionContext { + + /** + * Start this flow execution. This method should only be called once. + *

+ * When this method returns, execution status is either "paused" or "ended". If ended, the flow execution cannot be + * used again. If "paused", the flow execution may be {@link #resume(ExternalContext) resumed}. + * @param input flow execution input + * @param context the external context representing the calling environment + * @throws FlowExecutionException if an exception was thrown within a state of the flow execution during request + * processing + */ + void start(MutableAttributeMap input, ExternalContext context) throws FlowExecutionException; + + /** + * Resume this flow execution. May be called when the flow execution is paused. + * + * When this method returns, execution status is either "paused" or "ended". If ended, the flow execution cannot be + * used again. If "paused", the flow execution may be resumed again. + * @param context the external context, representing the calling environment, where something happened this flow + * execution should respond to + * @throws FlowExecutionException if an exception was thrown within a state of the resumed flow execution during + * event processing + */ + void resume(ExternalContext context) throws FlowExecutionException; + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionContext.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionContext.java index f6b89e4f..a50e55e6 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionContext.java @@ -1,120 +1,120 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; - -/** - * Provides contextual information about a flow execution. A flow execution is an runnable instance of a - * {@link FlowDefinition}. It is the central Spring Web Flow construct for carrying out a conversation with a client. - * This immutable interface provides access to runtime information about the conversation, such as it's - * {@link #isActive() status} and {@link #getActiveSession() current state}. - *

- * An object implementing this interface is also traversable from a execution request context (see - * {@link org.springframework.webflow.execution.RequestContext#getFlowExecutionContext()}). - *

- * This interface provides information that may span more than one request in a thread safe manner. The - * {@link RequestContext} interface defines a request specific control interface for manipulating exactly one - * flow execution locally from exactly one request. - * - * @see FlowDefinition - * @see FlowSession - * @see RequestContext - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface FlowExecutionContext { - - /** - * Returns the key assigned to this flow execution. The flow execution key is the flow execution's persistent - * identity. - * @return the flow execution key; may be null if a key has not yet been assigned. - */ - FlowExecutionKey getKey(); - - /** - * Returns the root flow definition associated with this executing flow. - *

- * A call to this method always returns the same flow definition -- the top-level "root" -- no matter what flow may - * actually be active (for example, if subflows have been spawned). - * @return the root flow definition - */ - FlowDefinition getDefinition(); - - /** - * Returns a flag indicating if this execution has been started. A flow execution that has started and is active is - * currently in progress. A flow execution that has started and is not active has ended. - * @see #isActive() - * @return true if started, false if not started - */ - boolean hasStarted(); - - /** - * Is the flow execution active? A flow execution is active once it has an {@link #getActiveSession() active - * session} and remains active until it has ended. - * @return true if active, false if the flow execution has terminated or has not yet been started - */ - boolean isActive(); - - /** - * Returns a flag indicating if this execution has ended. A flow execution that has ended has been started but is no - * longer active. - * @see #hasStarted() - * @see #isActive() - * @return true if ended, false if not started or still active - */ - boolean hasEnded(); - - /** - * Returns the outcome reached by this execution, or null if this execution has not yet ended. - * @return the outcome, or null if this execution has not yet ended - */ - FlowExecutionOutcome getOutcome(); - - /** - * Returns the active flow session of this flow execution. The active flow session is the currently executing - * session. It may be the "root flow" session, or it may be a subflow session if this flow execution has spawned a - * subflow. - * @return the active flow session - * @throws IllegalStateException if this flow execution is not active - * @see #isActive() - */ - FlowSession getActiveSession() throws IllegalStateException; - - /** - * Returns a mutable map for data held in "flash scope". Attributes in this map are cleared out on the next view - * rendering. Flash attributes survive flow execution refresh operations. - * @return flash scope - */ - MutableAttributeMap getFlashScope(); - - /** - * Returns a mutable map for data held in "conversation scope". Conversation scope is a data structure that exists - * for the life of this flow execution and is accessible to all flow sessions. - * @return conversation scope - */ - MutableAttributeMap getConversationScope(); - - /** - * Returns runtime execution attributes that may influence the behavior of flow artifacts, such as states and - * actions. - * @return execution attributes - */ - AttributeMap getAttributes(); -} +/* + * Copyright 2004-2012 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 + * + * https://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; + +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; + +/** + * Provides contextual information about a flow execution. A flow execution is an runnable instance of a + * {@link FlowDefinition}. It is the central Spring Web Flow construct for carrying out a conversation with a client. + * This immutable interface provides access to runtime information about the conversation, such as it's + * {@link #isActive() status} and {@link #getActiveSession() current state}. + *

+ * An object implementing this interface is also traversable from a execution request context (see + * {@link org.springframework.webflow.execution.RequestContext#getFlowExecutionContext()}). + *

+ * This interface provides information that may span more than one request in a thread safe manner. The + * {@link RequestContext} interface defines a request specific control interface for manipulating exactly one + * flow execution locally from exactly one request. + * + * @see FlowDefinition + * @see FlowSession + * @see RequestContext + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface FlowExecutionContext { + + /** + * Returns the key assigned to this flow execution. The flow execution key is the flow execution's persistent + * identity. + * @return the flow execution key; may be null if a key has not yet been assigned. + */ + FlowExecutionKey getKey(); + + /** + * Returns the root flow definition associated with this executing flow. + *

+ * A call to this method always returns the same flow definition -- the top-level "root" -- no matter what flow may + * actually be active (for example, if subflows have been spawned). + * @return the root flow definition + */ + FlowDefinition getDefinition(); + + /** + * Returns a flag indicating if this execution has been started. A flow execution that has started and is active is + * currently in progress. A flow execution that has started and is not active has ended. + * @see #isActive() + * @return true if started, false if not started + */ + boolean hasStarted(); + + /** + * Is the flow execution active? A flow execution is active once it has an {@link #getActiveSession() active + * session} and remains active until it has ended. + * @return true if active, false if the flow execution has terminated or has not yet been started + */ + boolean isActive(); + + /** + * Returns a flag indicating if this execution has ended. A flow execution that has ended has been started but is no + * longer active. + * @see #hasStarted() + * @see #isActive() + * @return true if ended, false if not started or still active + */ + boolean hasEnded(); + + /** + * Returns the outcome reached by this execution, or null if this execution has not yet ended. + * @return the outcome, or null if this execution has not yet ended + */ + FlowExecutionOutcome getOutcome(); + + /** + * Returns the active flow session of this flow execution. The active flow session is the currently executing + * session. It may be the "root flow" session, or it may be a subflow session if this flow execution has spawned a + * subflow. + * @return the active flow session + * @throws IllegalStateException if this flow execution is not active + * @see #isActive() + */ + FlowSession getActiveSession() throws IllegalStateException; + + /** + * Returns a mutable map for data held in "flash scope". Attributes in this map are cleared out on the next view + * rendering. Flash attributes survive flow execution refresh operations. + * @return flash scope + */ + MutableAttributeMap getFlashScope(); + + /** + * Returns a mutable map for data held in "conversation scope". Conversation scope is a data structure that exists + * for the life of this flow execution and is accessible to all flow sessions. + * @return conversation scope + */ + MutableAttributeMap getConversationScope(); + + /** + * Returns runtime execution attributes that may influence the behavior of flow artifacts, such as states and + * actions. + * @return execution attributes + */ + AttributeMap getAttributes(); +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionException.java index dcea54dc..1a8bef53 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionException.java @@ -1,81 +1,81 @@ -/* - * 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 - * - * https://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; - -import org.springframework.webflow.core.FlowException; - -/** - * Base class for exceptions that occur within a flow while it is executing. Can be used directly, but you are - * encouraged to create a specific subclass for a particular use case. - *

- * Execution exceptions occur at runtime when the flow is executing requests on behalf of a client. They signal that an - * execution problem occurred: e.g. action execution failed or no transition matched the current request context. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class FlowExecutionException extends FlowException { - - /** - * The id of the flow definition in which the exception occurred. - */ - private String flowId; - - /** - * The state of the flow where the exception occurred (optional). - */ - private String stateId; - - /** - * Creates a new flow execution exception. - * @param flowId the flow where the exception occurred - * @param stateId the state where the exception occurred - * @param message a descriptive message - */ - public FlowExecutionException(String flowId, String stateId, String message) { - super(message); - this.stateId = stateId; - this.flowId = flowId; - } - - /** - * Creates a new flow execution exception. - * @param flowId the flow where the exception occured - * @param stateId the state where the exception occured - * @param message a descriptive message - * @param cause the root cause - */ - public FlowExecutionException(String flowId, String stateId, String message, Throwable cause) { - super(message, cause); - this.stateId = stateId; - this.flowId = flowId; - } - - /** - * Returns the id of the flow definition that was executing when this exception occured. - */ - public String getFlowId() { - return flowId; - } - - /** - * Returns the id of the state definition where the exception occured. Could be null if no state was active at the - * time when the exception was thrown. - */ - public String getStateId() { - return stateId; - } +/* + * 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 + * + * https://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; + +import org.springframework.webflow.core.FlowException; + +/** + * Base class for exceptions that occur within a flow while it is executing. Can be used directly, but you are + * encouraged to create a specific subclass for a particular use case. + *

+ * Execution exceptions occur at runtime when the flow is executing requests on behalf of a client. They signal that an + * execution problem occurred: e.g. action execution failed or no transition matched the current request context. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class FlowExecutionException extends FlowException { + + /** + * The id of the flow definition in which the exception occurred. + */ + private String flowId; + + /** + * The state of the flow where the exception occurred (optional). + */ + private String stateId; + + /** + * Creates a new flow execution exception. + * @param flowId the flow where the exception occurred + * @param stateId the state where the exception occurred + * @param message a descriptive message + */ + public FlowExecutionException(String flowId, String stateId, String message) { + super(message); + this.stateId = stateId; + this.flowId = flowId; + } + + /** + * Creates a new flow execution exception. + * @param flowId the flow where the exception occured + * @param stateId the state where the exception occured + * @param message a descriptive message + * @param cause the root cause + */ + public FlowExecutionException(String flowId, String stateId, String message, Throwable cause) { + super(message, cause); + this.stateId = stateId; + this.flowId = flowId; + } + + /** + * Returns the id of the flow definition that was executing when this exception occured. + */ + public String getFlowId() { + return flowId; + } + + /** + * Returns the id of the state definition where the exception occured. Could be null if no state was active at the + * time when the exception was thrown. + */ + public String getStateId() { + return stateId; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionFactory.java index dcb35688..fc30bc87 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowExecutionFactory.java @@ -1,61 +1,61 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.registry.FlowDefinitionLocator; - -/** - * An abstract factory for creating flow executions. A flow execution represents a runtime, top-level instance of a flow - * definition. - *

- * This factory provides encapsulation of the flow execution implementation type, as well as its construction and - * assembly process. - *

- * Flow execution factories are responsible for registering {@link FlowExecutionListener listeners} with the constructed - * flow execution. - * - * @see FlowExecution - * @see FlowDefinition - * @see FlowExecutionListener - * - * @author Keith Donald - */ -public interface FlowExecutionFactory { - - /** - * Create a new flow execution product for the given flow definition. - * @param flowDefinition the flow definition - * @return the new flow execution, fully initialized and awaiting to be started - */ - FlowExecution createFlowExecution(FlowDefinition flowDefinition); - - /** - * Restore the transient state of the flow execution. - * @param flowExecution the flow execution, newly deserialized and needing restoration - * @param flowDefinition the root flow definition for the execution, typically not part of the serialized form - * @param flowExecutionKey the flow execution key, typically not part of the serialized form - * @param conversationScope the execution's conversation scope, which is typically not part of the serialized form - * since it could be shared by multiple physical flow execution copies all sharing the same logical - * conversation - * @param subflowDefinitionLocator for locating the definitions of any subflows started by the execution - * @return the restored flow execution - */ - FlowExecution restoreFlowExecution(FlowExecution flowExecution, FlowDefinition flowDefinition, - FlowExecutionKey flowExecutionKey, MutableAttributeMap conversationScope, - FlowDefinitionLocator subflowDefinitionLocator); -} +/* + * Copyright 2004-2012 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 + * + * https://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; + +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.registry.FlowDefinitionLocator; + +/** + * An abstract factory for creating flow executions. A flow execution represents a runtime, top-level instance of a flow + * definition. + *

+ * This factory provides encapsulation of the flow execution implementation type, as well as its construction and + * assembly process. + *

+ * Flow execution factories are responsible for registering {@link FlowExecutionListener listeners} with the constructed + * flow execution. + * + * @see FlowExecution + * @see FlowDefinition + * @see FlowExecutionListener + * + * @author Keith Donald + */ +public interface FlowExecutionFactory { + + /** + * Create a new flow execution product for the given flow definition. + * @param flowDefinition the flow definition + * @return the new flow execution, fully initialized and awaiting to be started + */ + FlowExecution createFlowExecution(FlowDefinition flowDefinition); + + /** + * Restore the transient state of the flow execution. + * @param flowExecution the flow execution, newly deserialized and needing restoration + * @param flowDefinition the root flow definition for the execution, typically not part of the serialized form + * @param flowExecutionKey the flow execution key, typically not part of the serialized form + * @param conversationScope the execution's conversation scope, which is typically not part of the serialized form + * since it could be shared by multiple physical flow execution copies all sharing the same logical + * conversation + * @param subflowDefinitionLocator for locating the definitions of any subflows started by the execution + * @return the restored flow execution + */ + FlowExecution restoreFlowExecution(FlowExecution flowExecution, FlowDefinition flowDefinition, + FlowExecutionKey flowExecutionKey, MutableAttributeMap conversationScope, + FlowDefinitionLocator subflowDefinitionLocator); +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowSession.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowSession.java index bf410cb1..3f5ec8bd 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowSession.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/FlowSession.java @@ -1,83 +1,83 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.StateDefinition; - -/** - * A single, local instantiation of a {@link FlowDefinition flow definition} launched within an overall flow execution. - *

- * This object maintains all instance state including session status within exactly one governing FlowExecution, as well - * as the current flow state. This object also acts as the local "flow scope" data model. Data in {@link #getScope() - * flow scope} lives for the life of this object and is cleaned up automatically when this object is destroyed. - * Destruction happens when this session enters an end state. - *

- * Note that a flow session is in no way linked to an HTTP session. It just uses the familiar "session" naming - * convention to denote a stateful object. - * - * @see FlowDefinition - * @see FlowExecution - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface FlowSession { - - /** - * Returns the flow definition backing this session. - */ - FlowDefinition getDefinition(); - - /** - * Returns the current state of this flow session. This value changes as the flow executes. - */ - StateDefinition getState(); - - /** - * Return this session's local attributes; the basis for "flow scope" (flow session scope). - * @return the flow scope attributes - */ - MutableAttributeMap getScope(); - - /** - * Returns a mutable map for data held in "view scope". Attributes in this map are cleared out when the current view - * state exits. - * @return view scope - * @throws IllegalStateException if this flow session is not currently in a view state - */ - MutableAttributeMap getViewScope() throws IllegalStateException; - - /** - * Returns true if the flow session was started in embedded page mode. An embedded flow can make different - * assumptions with regards to whether redirect after post is necessary. - */ - boolean isEmbeddedMode(); - - /** - * Returns the parent flow session in the current flow execution, or null if there is no parent flow - * session. - */ - FlowSession getParent(); - - /** - * Returns whether this flow session is the root flow session in the ongoing flow execution. The root flow session - * does not have a parent flow session. - */ - boolean isRoot(); - -} +/* + * Copyright 2004-2012 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 + * + * https://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; + +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.StateDefinition; + +/** + * A single, local instantiation of a {@link FlowDefinition flow definition} launched within an overall flow execution. + *

+ * This object maintains all instance state including session status within exactly one governing FlowExecution, as well + * as the current flow state. This object also acts as the local "flow scope" data model. Data in {@link #getScope() + * flow scope} lives for the life of this object and is cleaned up automatically when this object is destroyed. + * Destruction happens when this session enters an end state. + *

+ * Note that a flow session is in no way linked to an HTTP session. It just uses the familiar "session" naming + * convention to denote a stateful object. + * + * @see FlowDefinition + * @see FlowExecution + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface FlowSession { + + /** + * Returns the flow definition backing this session. + */ + FlowDefinition getDefinition(); + + /** + * Returns the current state of this flow session. This value changes as the flow executes. + */ + StateDefinition getState(); + + /** + * Return this session's local attributes; the basis for "flow scope" (flow session scope). + * @return the flow scope attributes + */ + MutableAttributeMap getScope(); + + /** + * Returns a mutable map for data held in "view scope". Attributes in this map are cleared out when the current view + * state exits. + * @return view scope + * @throws IllegalStateException if this flow session is not currently in a view state + */ + MutableAttributeMap getViewScope() throws IllegalStateException; + + /** + * Returns true if the flow session was started in embedded page mode. An embedded flow can make different + * assumptions with regards to whether redirect after post is necessary. + */ + boolean isEmbeddedMode(); + + /** + * Returns the parent flow session in the current flow execution, or null if there is no parent flow + * session. + */ + FlowSession getParent(); + + /** + * Returns whether this flow session is the root flow session in the ongoing flow execution. The root flow session + * does not have a parent flow session. + */ + boolean isRoot(); + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/RequestContext.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/RequestContext.java index 84c45c5e..c3197cdd 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/RequestContext.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/RequestContext.java @@ -1,211 +1,211 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -import org.springframework.binding.message.MessageContext; -import org.springframework.webflow.context.ExternalContext; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.core.collection.ParameterMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.StateDefinition; -import org.springframework.webflow.definition.TransitionDefinition; - -/** - * A context for a single request to manipulate a flow execution. Allows Web Flow users to access contextual information - * about the executing request, as well as the governing {@link #getFlowExecutionContext() active flow execution}. - *

- * The term request is used to describe a single call (thread) into the flow system by an external actor to - * manipulate exactly one flow execution. - *

- * A new instance of this object is typically created when one of the core operations supported by a flow execution is - * invoked, either start to launch the flow execution, signalEvent to resume the flow - * execution, or refresh to reconstitute the flow execution's last view selection for purposes of reissuing - * a user response. - *

- * Once created this context object is passed around throughout flow execution request processing where it may be - * accessed and reasoned upon by SWF-internal artifacts such as states, user-implemented action code, and state - * transition criteria. - *

- * When a call into a flow execution returns this object goes out of scope and is disposed of automatically. Thus a - * request context is an internal artifact used within a FlowExecution: this object is not exposed to external client - * code, e.g. a view implementation (JSP). - *

- * The {@link #getRequestScope() requestScope} property may be used as a store for arbitrary data that should exist for - * the life of this object. - *

- * The web flow system will ensure that a RequestContext object is local to the current thread. It can be safely - * manipulated without needing to worry about concurrent access. - *

- * Note: this request context is in no way linked to an HTTP request. It uses the familiar "request" naming - * convention to indicate a single call to manipulate a runtime execution of a flow definition. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface RequestContext { - - /** - * Returns the definition of the flow that is currently executing. - * @return the flow definition for the active session - * @throws IllegalStateException if the flow execution is not active - * @see FlowExecutionContext#isActive() - */ - FlowDefinition getActiveFlow() throws IllegalStateException; - - /** - * Returns the current state of the executing flow. Returns null if the active flow's start state has - * not yet been entered. - * @return the current state, or null if in the process of starting - * @throws IllegalStateException if this flow execution is not active - * @see FlowExecutionContext#isActive() - */ - StateDefinition getCurrentState() throws IllegalStateException; - - /** - * Returns the transition that would execute on the occurrence of the given event. - * @param eventId the id of the user event - * @return the transition that would trigger, or null if no transition matches - * @throws IllegalStateException if this flow execution is not active - * @see FlowExecutionContext#isActive() - */ - TransitionDefinition getMatchingTransition(String eventId) throws IllegalStateException; - - /** - * Returns true if the flow is currently active and in a view state. When in a view state {@link #getViewScope()}, - * can be safely called. - * @see #getViewScope() - * @return true if in a view state, false if not - */ - boolean inViewState(); - - /** - * Returns a mutable map for accessing and/or setting attributes in request scope. Request scoped attributes - * exist for the duration of this request only. - * @return the request scope - */ - MutableAttributeMap getRequestScope(); - - /** - * Returns a mutable map for accessing and/or setting attributes in flash scope. Flash scoped attributes exist - * until the next event is signaled in the flow execution. - * @return the flash scope - */ - MutableAttributeMap getFlashScope(); - - /** - * Returns a mutable map for accessing and/or setting attributes in view scope. View scoped attributes exist for - * the life of the current view state. - * @return the view scope - * @see #inViewState() - * @throws IllegalStateException if this flow is not in a view-state or the flow execution is not active - * @see FlowExecutionContext#isActive() - */ - MutableAttributeMap getViewScope() throws IllegalStateException; - - /** - * Returns a mutable map for accessing and/or setting attributes in flow scope. Flow scoped attributes exist for - * the life of the active flow session. - * @return the flow scope - * @see FlowSession - * @throws IllegalStateException if the flow execution is not active - * @see FlowExecutionContext#isActive() - */ - MutableAttributeMap getFlowScope() throws IllegalStateException; - - /** - * Returns a mutable accessor for accessing and/or setting attributes in conversation scope. Conversation scoped - * attributes exist for the life of the executing flow and are shared across all flow sessions. - * @return the conversation scope - * @see FlowExecutionContext - */ - MutableAttributeMap getConversationScope(); - - /** - * Returns the immutable input parameters associated with this request into Spring Web Flow. The map returned is - * immutable and cannot be changed. - *

- * This is typically a convenient shortcut for accessing the {@link ExternalContext#getRequestParameterMap()} - * directly. - * @see #getExternalContext() - */ - ParameterMap getRequestParameters(); - - /** - * Returns the external client context that originated (or triggered) this request. - *

- * Acting as a facade, the returned context object provides a single point of access to the calling client's - * environment. It provides normalized access to attributes of the client environment without tying you to specific - * constructs within that environment. - *

- * In addition, this context may be downcastable to a specific context type for a specific client environment, such - * as Servlets. Such downcasting will give you full access to a native HttpServletRequest, for example. - * With that said, for portability reasons you should avoid coupling your flow artifacts to a specific deployment - * environment when possible. - * @return the originating external context, the one that triggered the current execution request - */ - ExternalContext getExternalContext(); - - /** - * Returns the message context of this request. Useful for recording messages during the course of flow execution - * for display to the client. - * @return the message context - */ - MessageContext getMessageContext(); - - /** - * Returns contextual information about the flow execution itself. Information in this context typically spans more - * than one request. - * @return the flow execution context - */ - FlowExecutionContext getFlowExecutionContext(); - - /** - * Returns the current event being processed by this flow. The event may or may not have caused a state transition - * to happen. - * @return the current event, or null if no event has been signaled yet - */ - Event getCurrentEvent(); - - /** - * Returns the current transition executing in this request. - * @return the current transition, or null if no transition has occurred yet - */ - TransitionDefinition getCurrentTransition(); - - /** - * Returns the current view in use; if not null, the view returned is about to be rendered, is rendering, is - * processing a user event, or has finished user event processing and the current ViewState is exiting due to a - * state transition. Returns null if the flow is not in a view state. - * @return the current view, or null if the flow is not in a view state - */ - View getCurrentView(); - - /** - * Returns a context map for accessing attributes about the state of the current request. These attributes may be - * used to influence flow execution behavior. - * @return the current attributes of this request, or empty if none are set - */ - MutableAttributeMap getAttributes(); - - /** - * Returns the URL of this flow execution. Needed by response writers that write out the URL of this flow execution - * to allow calling back this execution in a subsequent request. - * @throws IllegalStateException if the flow execution has not yet had its key assigned - * @return the flow execution URL - */ - String getFlowExecutionUrl() throws IllegalStateException; - -} +/* + * Copyright 2004-2012 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 + * + * https://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; + +import org.springframework.binding.message.MessageContext; +import org.springframework.webflow.context.ExternalContext; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.core.collection.ParameterMap; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.StateDefinition; +import org.springframework.webflow.definition.TransitionDefinition; + +/** + * A context for a single request to manipulate a flow execution. Allows Web Flow users to access contextual information + * about the executing request, as well as the governing {@link #getFlowExecutionContext() active flow execution}. + *

+ * The term request is used to describe a single call (thread) into the flow system by an external actor to + * manipulate exactly one flow execution. + *

+ * A new instance of this object is typically created when one of the core operations supported by a flow execution is + * invoked, either start to launch the flow execution, signalEvent to resume the flow + * execution, or refresh to reconstitute the flow execution's last view selection for purposes of reissuing + * a user response. + *

+ * Once created this context object is passed around throughout flow execution request processing where it may be + * accessed and reasoned upon by SWF-internal artifacts such as states, user-implemented action code, and state + * transition criteria. + *

+ * When a call into a flow execution returns this object goes out of scope and is disposed of automatically. Thus a + * request context is an internal artifact used within a FlowExecution: this object is not exposed to external client + * code, e.g. a view implementation (JSP). + *

+ * The {@link #getRequestScope() requestScope} property may be used as a store for arbitrary data that should exist for + * the life of this object. + *

+ * The web flow system will ensure that a RequestContext object is local to the current thread. It can be safely + * manipulated without needing to worry about concurrent access. + *

+ * Note: this request context is in no way linked to an HTTP request. It uses the familiar "request" naming + * convention to indicate a single call to manipulate a runtime execution of a flow definition. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface RequestContext { + + /** + * Returns the definition of the flow that is currently executing. + * @return the flow definition for the active session + * @throws IllegalStateException if the flow execution is not active + * @see FlowExecutionContext#isActive() + */ + FlowDefinition getActiveFlow() throws IllegalStateException; + + /** + * Returns the current state of the executing flow. Returns null if the active flow's start state has + * not yet been entered. + * @return the current state, or null if in the process of starting + * @throws IllegalStateException if this flow execution is not active + * @see FlowExecutionContext#isActive() + */ + StateDefinition getCurrentState() throws IllegalStateException; + + /** + * Returns the transition that would execute on the occurrence of the given event. + * @param eventId the id of the user event + * @return the transition that would trigger, or null if no transition matches + * @throws IllegalStateException if this flow execution is not active + * @see FlowExecutionContext#isActive() + */ + TransitionDefinition getMatchingTransition(String eventId) throws IllegalStateException; + + /** + * Returns true if the flow is currently active and in a view state. When in a view state {@link #getViewScope()}, + * can be safely called. + * @see #getViewScope() + * @return true if in a view state, false if not + */ + boolean inViewState(); + + /** + * Returns a mutable map for accessing and/or setting attributes in request scope. Request scoped attributes + * exist for the duration of this request only. + * @return the request scope + */ + MutableAttributeMap getRequestScope(); + + /** + * Returns a mutable map for accessing and/or setting attributes in flash scope. Flash scoped attributes exist + * until the next event is signaled in the flow execution. + * @return the flash scope + */ + MutableAttributeMap getFlashScope(); + + /** + * Returns a mutable map for accessing and/or setting attributes in view scope. View scoped attributes exist for + * the life of the current view state. + * @return the view scope + * @see #inViewState() + * @throws IllegalStateException if this flow is not in a view-state or the flow execution is not active + * @see FlowExecutionContext#isActive() + */ + MutableAttributeMap getViewScope() throws IllegalStateException; + + /** + * Returns a mutable map for accessing and/or setting attributes in flow scope. Flow scoped attributes exist for + * the life of the active flow session. + * @return the flow scope + * @see FlowSession + * @throws IllegalStateException if the flow execution is not active + * @see FlowExecutionContext#isActive() + */ + MutableAttributeMap getFlowScope() throws IllegalStateException; + + /** + * Returns a mutable accessor for accessing and/or setting attributes in conversation scope. Conversation scoped + * attributes exist for the life of the executing flow and are shared across all flow sessions. + * @return the conversation scope + * @see FlowExecutionContext + */ + MutableAttributeMap getConversationScope(); + + /** + * Returns the immutable input parameters associated with this request into Spring Web Flow. The map returned is + * immutable and cannot be changed. + *

+ * This is typically a convenient shortcut for accessing the {@link ExternalContext#getRequestParameterMap()} + * directly. + * @see #getExternalContext() + */ + ParameterMap getRequestParameters(); + + /** + * Returns the external client context that originated (or triggered) this request. + *

+ * Acting as a facade, the returned context object provides a single point of access to the calling client's + * environment. It provides normalized access to attributes of the client environment without tying you to specific + * constructs within that environment. + *

+ * In addition, this context may be downcastable to a specific context type for a specific client environment, such + * as Servlets. Such downcasting will give you full access to a native HttpServletRequest, for example. + * With that said, for portability reasons you should avoid coupling your flow artifacts to a specific deployment + * environment when possible. + * @return the originating external context, the one that triggered the current execution request + */ + ExternalContext getExternalContext(); + + /** + * Returns the message context of this request. Useful for recording messages during the course of flow execution + * for display to the client. + * @return the message context + */ + MessageContext getMessageContext(); + + /** + * Returns contextual information about the flow execution itself. Information in this context typically spans more + * than one request. + * @return the flow execution context + */ + FlowExecutionContext getFlowExecutionContext(); + + /** + * Returns the current event being processed by this flow. The event may or may not have caused a state transition + * to happen. + * @return the current event, or null if no event has been signaled yet + */ + Event getCurrentEvent(); + + /** + * Returns the current transition executing in this request. + * @return the current transition, or null if no transition has occurred yet + */ + TransitionDefinition getCurrentTransition(); + + /** + * Returns the current view in use; if not null, the view returned is about to be rendered, is rendering, is + * processing a user event, or has finished user event processing and the current ViewState is exiting due to a + * state transition. Returns null if the flow is not in a view state. + * @return the current view, or null if the flow is not in a view state + */ + View getCurrentView(); + + /** + * Returns a context map for accessing attributes about the state of the current request. These attributes may be + * used to influence flow execution behavior. + * @return the current attributes of this request, or empty if none are set + */ + MutableAttributeMap getAttributes(); + + /** + * Returns the URL of this flow execution. Needed by response writers that write out the URL of this flow execution + * to allow calling back this execution in a subsequent request. + * @throws IllegalStateException if the flow execution has not yet had its key assigned + * @return the flow execution URL + */ + String getFlowExecutionUrl() throws IllegalStateException; + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/ScopeType.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/ScopeType.java index 0ee22f1f..c89b258b 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/ScopeType.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/ScopeType.java @@ -1,101 +1,101 @@ -/* - * Copyright 2004-2012 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 - * - * https://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; - -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; - -/** - * An enumeration of the core scope types of Spring Web Flow. Provides easy access to each scope by type using - * {@link #getScope(RequestContext)}. - *

- * A "scope" defines a data structure for storing custom user attributes within a flow execution. Different scope types - * have different semantics in terms of how long attributes placed in those scope maps remain valid. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public enum ScopeType { - - /** - * The "request" scope type. Attributes placed in request scope exist for the life of the current request into the - * flow execution. When the request ends any attributes in request scope go out of scope. - */ - REQUEST() { - public MutableAttributeMap getScope(RequestContext context) { - return context.getRequestScope(); - } - }, - - /** - * The "flash" scope type. Attributes placed in flash scope exist through the life of the current request and - * until the next view rendering. After the view renders, flash scope is cleared. - *

- * Flash scope is typically used to store messages that should be preserved until after the next view renders. - */ - FLASH() { - public MutableAttributeMap getScope(RequestContext context) { - return context.getFlashScope(); - } - }, - - /** - * The "view" scope type. Attributes placed in view scope exist through the life of the current view state and - * until the view state exits in a subsequent request. - *

- * View scope is typically used to store view model objects manipulated over a series of Ajax requests. - */ - VIEW() { - public MutableAttributeMap getScope(RequestContext context) { - return context.getViewScope(); - } - }, - - /** - * The "flow" scope type. Attributes placed in flow scope exist through the life of an executing flow session, - * representing an instance a single {@link FlowDefinition flow definition}. When the flow session ends any data in - * flow scope goes out of scope. - */ - FLOW() { - public MutableAttributeMap getScope(RequestContext context) { - return context.getFlowScope(); - } - }, - - /** - * The "conversation" scope type. Attributes placed in conversation scope are shared by all flow sessions started - * within a flow execution and live for the life of the entire flow execution (representing a single logical user - * conversation). When the governing execution ends, any data in conversation scope goes out of scope. - */ - CONVERSATION() { - public MutableAttributeMap getScope(RequestContext context) { - return context.getConversationScope(); - } - }; - - public Class getType() { - // force ScopeType as type - return ScopeType.class; - } - - /** - * Accessor that returns the mutable attribute map for this scope type for a given flow execution request context. - * @param context the context representing an executing request - * @return the scope map of this type for that request, allowing attributes to be accessed and set - */ - public abstract MutableAttributeMap getScope(RequestContext context); - +/* + * Copyright 2004-2012 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 + * + * https://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; + +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; + +/** + * An enumeration of the core scope types of Spring Web Flow. Provides easy access to each scope by type using + * {@link #getScope(RequestContext)}. + *

+ * A "scope" defines a data structure for storing custom user attributes within a flow execution. Different scope types + * have different semantics in terms of how long attributes placed in those scope maps remain valid. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public enum ScopeType { + + /** + * The "request" scope type. Attributes placed in request scope exist for the life of the current request into the + * flow execution. When the request ends any attributes in request scope go out of scope. + */ + REQUEST() { + public MutableAttributeMap getScope(RequestContext context) { + return context.getRequestScope(); + } + }, + + /** + * The "flash" scope type. Attributes placed in flash scope exist through the life of the current request and + * until the next view rendering. After the view renders, flash scope is cleared. + *

+ * Flash scope is typically used to store messages that should be preserved until after the next view renders. + */ + FLASH() { + public MutableAttributeMap getScope(RequestContext context) { + return context.getFlashScope(); + } + }, + + /** + * The "view" scope type. Attributes placed in view scope exist through the life of the current view state and + * until the view state exits in a subsequent request. + *

+ * View scope is typically used to store view model objects manipulated over a series of Ajax requests. + */ + VIEW() { + public MutableAttributeMap getScope(RequestContext context) { + return context.getViewScope(); + } + }, + + /** + * The "flow" scope type. Attributes placed in flow scope exist through the life of an executing flow session, + * representing an instance a single {@link FlowDefinition flow definition}. When the flow session ends any data in + * flow scope goes out of scope. + */ + FLOW() { + public MutableAttributeMap getScope(RequestContext context) { + return context.getFlowScope(); + } + }, + + /** + * The "conversation" scope type. Attributes placed in conversation scope are shared by all flow sessions started + * within a flow execution and live for the life of the entire flow execution (representing a single logical user + * conversation). When the governing execution ends, any data in conversation scope goes out of scope. + */ + CONVERSATION() { + public MutableAttributeMap getScope(RequestContext context) { + return context.getConversationScope(); + } + }; + + public Class getType() { + // force ScopeType as type + return ScopeType.class; + } + + /** + * Accessor that returns the mutable attribute map for this scope type for a given flow execution request context. + * @param context the context representing an executing request + * @return the scope map of this type for that request, allowing attributes to be accessed and set + */ + public abstract MutableAttributeMap getScope(RequestContext context); + } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/ConditionalFlowExecutionListenerHolder.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/ConditionalFlowExecutionListenerHolder.java index 9b0501b2..26b89ecd 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/ConditionalFlowExecutionListenerHolder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/ConditionalFlowExecutionListenerHolder.java @@ -1,97 +1,97 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.factory; - -import java.util.LinkedHashSet; -import java.util.Set; - -import org.springframework.util.Assert; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.execution.FlowExecutionListener; - -/** - * A holder that holds a listener plus a set of criteria defining the flows in which that listener applies. - *

- * This is an internal helper class used by the {@link ConditionalFlowExecutionListenerLoader}. - * - * @see ConditionalFlowExecutionListenerLoader - * - * @author Keith Donald - */ -class ConditionalFlowExecutionListenerHolder { - - /** - * The held listener. - */ - private FlowExecutionListener listener; - - /** - * The listener criteria set. - */ - private Set criteriaSet = new LinkedHashSet<>(3); - - /** - * Create a new conditional flow execution listener holder. - * @param listener the listener to hold - */ - public ConditionalFlowExecutionListenerHolder(FlowExecutionListener listener) { - Assert.notNull(listener, "The listener is required"); - this.listener = listener; - } - - /** - * Returns the held listener. - */ - public FlowExecutionListener getListener() { - return listener; - } - - /** - * Add given criteria. - */ - public void add(FlowExecutionListenerCriteria criteria) { - criteriaSet.add(criteria); - } - - /** - * Remove given criteria. If not present, does nothing. - */ - public void remove(FlowExecutionListenerCriteria criteria) { - criteriaSet.remove(criteria); - } - - /** - * Are there any criteria registered? - */ - public boolean isCriteriaSetEmpty() { - return criteriaSet.isEmpty(); - } - - /** - * Determines if the listener held by this holder applies to the specified flow definition. Will do a logical OR - * between the registered criteria. - * @param flowDefinition the flow - * @return true if yes, false otherwise - */ - public boolean listenerAppliesTo(FlowDefinition flowDefinition) { - for (FlowExecutionListenerCriteria criteria : criteriaSet) { - if (criteria.appliesTo(flowDefinition)) { - return true; - } - } - return false; - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.factory; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.springframework.util.Assert; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.execution.FlowExecutionListener; + +/** + * A holder that holds a listener plus a set of criteria defining the flows in which that listener applies. + *

+ * This is an internal helper class used by the {@link ConditionalFlowExecutionListenerLoader}. + * + * @see ConditionalFlowExecutionListenerLoader + * + * @author Keith Donald + */ +class ConditionalFlowExecutionListenerHolder { + + /** + * The held listener. + */ + private FlowExecutionListener listener; + + /** + * The listener criteria set. + */ + private Set criteriaSet = new LinkedHashSet<>(3); + + /** + * Create a new conditional flow execution listener holder. + * @param listener the listener to hold + */ + public ConditionalFlowExecutionListenerHolder(FlowExecutionListener listener) { + Assert.notNull(listener, "The listener is required"); + this.listener = listener; + } + + /** + * Returns the held listener. + */ + public FlowExecutionListener getListener() { + return listener; + } + + /** + * Add given criteria. + */ + public void add(FlowExecutionListenerCriteria criteria) { + criteriaSet.add(criteria); + } + + /** + * Remove given criteria. If not present, does nothing. + */ + public void remove(FlowExecutionListenerCriteria criteria) { + criteriaSet.remove(criteria); + } + + /** + * Are there any criteria registered? + */ + public boolean isCriteriaSetEmpty() { + return criteriaSet.isEmpty(); + } + + /** + * Determines if the listener held by this holder applies to the specified flow definition. Will do a logical OR + * between the registered criteria. + * @param flowDefinition the flow + * @return true if yes, false otherwise + */ + public boolean listenerAppliesTo(FlowDefinition flowDefinition) { + for (FlowExecutionListenerCriteria criteria : criteriaSet) { + if (criteria.appliesTo(flowDefinition)) { + return true; + } + } + return false; + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/ConditionalFlowExecutionListenerLoader.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/ConditionalFlowExecutionListenerLoader.java index 04885941..5b3e50c4 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/ConditionalFlowExecutionListenerLoader.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/ConditionalFlowExecutionListenerLoader.java @@ -1,107 +1,107 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.factory; - -import java.util.LinkedList; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.core.style.StylerUtils; -import org.springframework.util.Assert; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.execution.FlowExecutionListener; - -/** - * A flow execution listener loader that stores listeners in a list-backed data structure and allows for configuration - * of which listeners should apply to which flow definitions. For trivial listener loading, see - * {@link StaticFlowExecutionListenerLoader}. - * - * @see FlowExecutionListenerCriteria - * @see StaticFlowExecutionListenerLoader - * - * @author Keith Donald - */ -public class ConditionalFlowExecutionListenerLoader implements FlowExecutionListenerLoader { - - private final Log logger = LogFactory.getLog(ConditionalFlowExecutionListenerLoader.class); - - /** - * The list of flow execution listeners containing {@link ConditionalFlowExecutionListenerHolder} objects. The list - * determines the conditions in which a single flow execution listener applies. - */ - private List listeners = new LinkedList<>(); - - /** - * Add a listener that will listen to executions to flows matching the specified criteria. - * @param listener the listener - * @param criteria the listener criteria - */ - public void addListener(FlowExecutionListener listener, FlowExecutionListenerCriteria criteria) { - if (listener == null) { - throw new IllegalArgumentException("The flow execution listener cannot be null"); - } - if (logger.isDebugEnabled()) { - logger.debug("Adding flow execution listener " + listener + " with criteria " + criteria); - } - ConditionalFlowExecutionListenerHolder conditional = getHolder(listener); - if (conditional == null) { - conditional = new ConditionalFlowExecutionListenerHolder(listener); - listeners.add(conditional); - } - if (criteria == null) { - criteria = new FlowExecutionListenerCriteriaFactory().allFlows(); - } - conditional.add(criteria); - } - - /** - * Returns the array of flow execution listeners for specified flow. - * @param flowDefinition the flow definition associated with the execution to be listened to - * @return the flow execution listeners that apply - */ - public FlowExecutionListener[] getListeners(FlowDefinition flowDefinition) { - Assert.notNull(flowDefinition, "The Flow to load listeners for cannot be null"); - List listenersToAttach = new LinkedList<>(); - for (ConditionalFlowExecutionListenerHolder listenerHolder : listeners) { - if (listenerHolder.listenerAppliesTo(flowDefinition)) { - listenersToAttach.add(listenerHolder.getListener()); - } - } - if (logger.isDebugEnabled()) { - logger.debug("Loaded [" + listenersToAttach.size() + "] of possible " + listeners.size() - + " listeners for this execution request for flow '" + flowDefinition.getId() - + "', the listeners to attach are " + StylerUtils.style(listenersToAttach)); - } - return listenersToAttach.toArray(new FlowExecutionListener[listenersToAttach.size()]); - } - - // internal helpers - - /** - * Lookup the listener criteria holder for the listener provided. - * @param listener the listener - * @return the holder, or null if not found - */ - private ConditionalFlowExecutionListenerHolder getHolder(FlowExecutionListener listener) { - for (ConditionalFlowExecutionListenerHolder holder : listeners) { - if (holder.getListener().equals(listener)) { - return holder; - } - } - return null; - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.factory; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.style.StylerUtils; +import org.springframework.util.Assert; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.execution.FlowExecutionListener; + +/** + * A flow execution listener loader that stores listeners in a list-backed data structure and allows for configuration + * of which listeners should apply to which flow definitions. For trivial listener loading, see + * {@link StaticFlowExecutionListenerLoader}. + * + * @see FlowExecutionListenerCriteria + * @see StaticFlowExecutionListenerLoader + * + * @author Keith Donald + */ +public class ConditionalFlowExecutionListenerLoader implements FlowExecutionListenerLoader { + + private final Log logger = LogFactory.getLog(ConditionalFlowExecutionListenerLoader.class); + + /** + * The list of flow execution listeners containing {@link ConditionalFlowExecutionListenerHolder} objects. The list + * determines the conditions in which a single flow execution listener applies. + */ + private List listeners = new LinkedList<>(); + + /** + * Add a listener that will listen to executions to flows matching the specified criteria. + * @param listener the listener + * @param criteria the listener criteria + */ + public void addListener(FlowExecutionListener listener, FlowExecutionListenerCriteria criteria) { + if (listener == null) { + throw new IllegalArgumentException("The flow execution listener cannot be null"); + } + if (logger.isDebugEnabled()) { + logger.debug("Adding flow execution listener " + listener + " with criteria " + criteria); + } + ConditionalFlowExecutionListenerHolder conditional = getHolder(listener); + if (conditional == null) { + conditional = new ConditionalFlowExecutionListenerHolder(listener); + listeners.add(conditional); + } + if (criteria == null) { + criteria = new FlowExecutionListenerCriteriaFactory().allFlows(); + } + conditional.add(criteria); + } + + /** + * Returns the array of flow execution listeners for specified flow. + * @param flowDefinition the flow definition associated with the execution to be listened to + * @return the flow execution listeners that apply + */ + public FlowExecutionListener[] getListeners(FlowDefinition flowDefinition) { + Assert.notNull(flowDefinition, "The Flow to load listeners for cannot be null"); + List listenersToAttach = new LinkedList<>(); + for (ConditionalFlowExecutionListenerHolder listenerHolder : listeners) { + if (listenerHolder.listenerAppliesTo(flowDefinition)) { + listenersToAttach.add(listenerHolder.getListener()); + } + } + if (logger.isDebugEnabled()) { + logger.debug("Loaded [" + listenersToAttach.size() + "] of possible " + listeners.size() + + " listeners for this execution request for flow '" + flowDefinition.getId() + + "', the listeners to attach are " + StylerUtils.style(listenersToAttach)); + } + return listenersToAttach.toArray(new FlowExecutionListener[listenersToAttach.size()]); + } + + // internal helpers + + /** + * Lookup the listener criteria holder for the listener provided. + * @param listener the listener + * @return the holder, or null if not found + */ + private ConditionalFlowExecutionListenerHolder getHolder(FlowExecutionListener listener) { + for (ConditionalFlowExecutionListenerHolder holder : listeners) { + if (holder.getListener().equals(listener)) { + return holder; + } + } + return null; + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerCriteria.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerCriteria.java index 9a5bf87b..900f3c54 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerCriteria.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerCriteria.java @@ -1,41 +1,41 @@ -/* - * 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 - * - * https://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.factory; - -import org.springframework.webflow.definition.FlowDefinition; - -/** - * Strategy interface that determines if a flow execution listener should attach to executions of a specific flow - * definition. - *

- * This selection strategy is typically used by the {@link FlowExecutionListenerLoader} to determine which listeners - * should apply to which flow definitions. - * - * @see org.springframework.webflow.execution.FlowExecutionListener - * @see org.springframework.webflow.execution.factory.FlowExecutionListenerLoader - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public interface FlowExecutionListenerCriteria { - - /** - * Do the listeners guarded by this criteria object apply to the provided flow definition? - * @param definition the flow definition - * @return true if yes, false if no - */ - boolean appliesTo(FlowDefinition definition); +/* + * 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 + * + * https://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.factory; + +import org.springframework.webflow.definition.FlowDefinition; + +/** + * Strategy interface that determines if a flow execution listener should attach to executions of a specific flow + * definition. + *

+ * This selection strategy is typically used by the {@link FlowExecutionListenerLoader} to determine which listeners + * should apply to which flow definitions. + * + * @see org.springframework.webflow.execution.FlowExecutionListener + * @see org.springframework.webflow.execution.factory.FlowExecutionListenerLoader + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public interface FlowExecutionListenerCriteria { + + /** + * Do the listeners guarded by this criteria object apply to the provided flow definition? + * @param definition the flow definition + * @return true if yes, false if no + */ + boolean appliesTo(FlowDefinition definition); } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerCriteriaFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerCriteriaFactory.java index 47c77040..41fb9309 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerCriteriaFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerCriteriaFactory.java @@ -1,117 +1,117 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.factory; - -import org.springframework.core.style.StylerUtils; -import org.springframework.core.style.ToStringCreator; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; -import org.springframework.webflow.definition.FlowDefinition; - -/** - * Static factory for creating commonly used flow execution listener criteria. - * - * @see FlowExecutionListenerCriteria - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class FlowExecutionListenerCriteriaFactory { - - private static final WildcardFlowExecutionListenerCriteria WILDCARD_INSTANCE = new WildcardFlowExecutionListenerCriteria(); - - public FlowExecutionListenerCriteria getListenerCriteria(String encodedCriteria) { - if ("*".equals(encodedCriteria)) { - return allFlows(); - } else { - String[] flowIds = StringUtils.commaDelimitedListToStringArray(encodedCriteria); - for (int i = 0; i < flowIds.length; i++) { - flowIds[i] = flowIds[i].trim(); - } - return flows(flowIds); - } - } - - /** - * Returns a wild card criteria that matches all flows. - */ - public FlowExecutionListenerCriteria allFlows() { - return WILDCARD_INSTANCE; - } - - /** - * Returns a criteria that just matches a flow with the specified id. - * @param flowId the flow id to match - */ - public FlowExecutionListenerCriteria flow(String flowId) { - return new FlowIdFlowExecutionListenerCriteria(flowId); - } - - /** - * Returns a criteria that just matches a flow if it is identified by one of the specified ids. - * @param flowIds the flow ids to match - */ - public FlowExecutionListenerCriteria flows(String... flowIds) { - return new FlowIdFlowExecutionListenerCriteria(flowIds); - } - - /** - * A flow execution listener criteria implementation that matches for all flows. - */ - private static class WildcardFlowExecutionListenerCriteria implements FlowExecutionListenerCriteria { - - public boolean appliesTo(FlowDefinition definition) { - return true; - } - - public String toString() { - return "*"; - } - } - - /** - * A flow execution listener criteria implementation that matches flows with a specified id. - */ - private static class FlowIdFlowExecutionListenerCriteria implements FlowExecutionListenerCriteria { - - /** - * The flow ids that apply for this criteria. - */ - private String[] flowIds; - - /** - * Create a new flow id matching flow execution listener criteria implementation. - * @param flowIds the flow ids to match - */ - public FlowIdFlowExecutionListenerCriteria(String... flowIds) { - Assert.notEmpty(flowIds, "The flow id array is required"); - this.flowIds = flowIds; - } - - public boolean appliesTo(FlowDefinition definition) { - for (String flowId : flowIds) { - if (flowId.equals(definition.getId())) { - return true; - } - } - return false; - } - - public String toString() { - return new ToStringCreator(this).append("flowIds", StylerUtils.style(flowIds)).toString(); - } - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.factory; + +import org.springframework.core.style.StylerUtils; +import org.springframework.core.style.ToStringCreator; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.webflow.definition.FlowDefinition; + +/** + * Static factory for creating commonly used flow execution listener criteria. + * + * @see FlowExecutionListenerCriteria + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class FlowExecutionListenerCriteriaFactory { + + private static final WildcardFlowExecutionListenerCriteria WILDCARD_INSTANCE = new WildcardFlowExecutionListenerCriteria(); + + public FlowExecutionListenerCriteria getListenerCriteria(String encodedCriteria) { + if ("*".equals(encodedCriteria)) { + return allFlows(); + } else { + String[] flowIds = StringUtils.commaDelimitedListToStringArray(encodedCriteria); + for (int i = 0; i < flowIds.length; i++) { + flowIds[i] = flowIds[i].trim(); + } + return flows(flowIds); + } + } + + /** + * Returns a wild card criteria that matches all flows. + */ + public FlowExecutionListenerCriteria allFlows() { + return WILDCARD_INSTANCE; + } + + /** + * Returns a criteria that just matches a flow with the specified id. + * @param flowId the flow id to match + */ + public FlowExecutionListenerCriteria flow(String flowId) { + return new FlowIdFlowExecutionListenerCriteria(flowId); + } + + /** + * Returns a criteria that just matches a flow if it is identified by one of the specified ids. + * @param flowIds the flow ids to match + */ + public FlowExecutionListenerCriteria flows(String... flowIds) { + return new FlowIdFlowExecutionListenerCriteria(flowIds); + } + + /** + * A flow execution listener criteria implementation that matches for all flows. + */ + private static class WildcardFlowExecutionListenerCriteria implements FlowExecutionListenerCriteria { + + public boolean appliesTo(FlowDefinition definition) { + return true; + } + + public String toString() { + return "*"; + } + } + + /** + * A flow execution listener criteria implementation that matches flows with a specified id. + */ + private static class FlowIdFlowExecutionListenerCriteria implements FlowExecutionListenerCriteria { + + /** + * The flow ids that apply for this criteria. + */ + private String[] flowIds; + + /** + * Create a new flow id matching flow execution listener criteria implementation. + * @param flowIds the flow ids to match + */ + public FlowIdFlowExecutionListenerCriteria(String... flowIds) { + Assert.notEmpty(flowIds, "The flow id array is required"); + this.flowIds = flowIds; + } + + public boolean appliesTo(FlowDefinition definition) { + for (String flowId : flowIds) { + if (flowId.equals(definition.getId())) { + return true; + } + } + return false; + } + + public String toString() { + return new ToStringCreator(this).append("flowIds", StylerUtils.style(flowIds)).toString(); + } + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerLoader.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerLoader.java index d879b4a1..b67d6d33 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerLoader.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/FlowExecutionListenerLoader.java @@ -1,36 +1,36 @@ -/* - * 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 - * - * https://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.factory; - -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.execution.FlowExecutionFactory; -import org.springframework.webflow.execution.FlowExecutionListener; - -/** - * A strategy interface for loading the set of FlowExecutionListener's that should apply to executions of a given flow - * definition. Typically used by a {@link FlowExecutionFactory} as part of execution creation. - * - * @author Keith Donald - */ -public interface FlowExecutionListenerLoader { - - /** - * Get the flow execution listeners that apply to the given flow definition. - * @param flowDefinition the flow definition - * @return the listeners that apply - */ - FlowExecutionListener[] getListeners(FlowDefinition flowDefinition); +/* + * 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 + * + * https://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.factory; + +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.execution.FlowExecutionFactory; +import org.springframework.webflow.execution.FlowExecutionListener; + +/** + * A strategy interface for loading the set of FlowExecutionListener's that should apply to executions of a given flow + * definition. Typically used by a {@link FlowExecutionFactory} as part of execution creation. + * + * @author Keith Donald + */ +public interface FlowExecutionListenerLoader { + + /** + * Get the flow execution listeners that apply to the given flow definition. + * @param flowDefinition the flow definition + * @return the listeners that apply + */ + FlowExecutionListener[] getListeners(FlowDefinition flowDefinition); } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/StaticFlowExecutionListenerLoader.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/StaticFlowExecutionListenerLoader.java index 837f0c2e..513311cf 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/StaticFlowExecutionListenerLoader.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/factory/StaticFlowExecutionListenerLoader.java @@ -1,70 +1,70 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.factory; - -import org.springframework.util.Assert; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.execution.FlowExecutionListener; - -/** - * A simple flow execution listener loader that simply returns a static listener array on each invocation. For more - * elaborate needs see the {@link ConditionalFlowExecutionListenerLoader}. - * - * @see ConditionalFlowExecutionListenerLoader - * - * @author Keith Donald - */ -public final class StaticFlowExecutionListenerLoader implements FlowExecutionListenerLoader { - - /** - * A shared listener loader instance that returns am empty listener array on each invocation. - */ - public static final FlowExecutionListenerLoader EMPTY_INSTANCE = new StaticFlowExecutionListenerLoader(); - - /** - * The listener array to return when {@link #getListeners(FlowDefinition)} is invoked. - */ - private final FlowExecutionListener[] listeners; - - /** - * Creates a new flow execution listener loader that returns the provided listener on each invocation. - * @param listener the listener - */ - public StaticFlowExecutionListenerLoader(FlowExecutionListener listener) { - this(new FlowExecutionListener[] { listener }); - } - - /** - * Creates a new flow execution listener loader that returns the provided listener array on each invocation. Clients - * should not attempt to modify the passed in array as no deep copy is made. - * @param listeners the listener array. - */ - public StaticFlowExecutionListenerLoader(FlowExecutionListener... listeners) { - Assert.notNull(listeners, "The flow execution listener array is required"); - this.listeners = listeners; - } - - /** - * Creates a new flow execution listener loader that returns an empty listener array on each invocation. - */ - private StaticFlowExecutionListenerLoader() { - this(new FlowExecutionListener[0]); - } - - public FlowExecutionListener[] getListeners(FlowDefinition flowDefinition) { - return listeners; - } +/* + * Copyright 2004-2012 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 + * + * https://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.factory; + +import org.springframework.util.Assert; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.execution.FlowExecutionListener; + +/** + * A simple flow execution listener loader that simply returns a static listener array on each invocation. For more + * elaborate needs see the {@link ConditionalFlowExecutionListenerLoader}. + * + * @see ConditionalFlowExecutionListenerLoader + * + * @author Keith Donald + */ +public final class StaticFlowExecutionListenerLoader implements FlowExecutionListenerLoader { + + /** + * A shared listener loader instance that returns am empty listener array on each invocation. + */ + public static final FlowExecutionListenerLoader EMPTY_INSTANCE = new StaticFlowExecutionListenerLoader(); + + /** + * The listener array to return when {@link #getListeners(FlowDefinition)} is invoked. + */ + private final FlowExecutionListener[] listeners; + + /** + * Creates a new flow execution listener loader that returns the provided listener on each invocation. + * @param listener the listener + */ + public StaticFlowExecutionListenerLoader(FlowExecutionListener listener) { + this(new FlowExecutionListener[] { listener }); + } + + /** + * Creates a new flow execution listener loader that returns the provided listener array on each invocation. Clients + * should not attempt to modify the passed in array as no deep copy is made. + * @param listeners the listener array. + */ + public StaticFlowExecutionListenerLoader(FlowExecutionListener... listeners) { + Assert.notNull(listeners, "The flow execution listener array is required"); + this.listeners = listeners; + } + + /** + * Creates a new flow execution listener loader that returns an empty listener array on each invocation. + */ + private StaticFlowExecutionListenerLoader() { + this(new FlowExecutionListener[0]); + } + + public FlowExecutionListener[] getListeners(FlowDefinition flowDefinition) { + return listeners; + } } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/BadlyFormattedFlowExecutionKeyException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/BadlyFormattedFlowExecutionKeyException.java index 1b58c9bf..22d19238 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/BadlyFormattedFlowExecutionKeyException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/BadlyFormattedFlowExecutionKeyException.java @@ -1,72 +1,72 @@ -/* - * 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 - * - * https://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; - -/** - * Thrown when an encoded flow execution key is badly formatted and could not be parsed. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class BadlyFormattedFlowExecutionKeyException extends FlowExecutionRepositoryException { - - /** - * The string encoded flow execution key that was invalid. - */ - private String invalidKey; - - /** - * The format the string key should have been in. Could just be a description of that format. - */ - private String format; - - /** - * Creates a bad execution key format exception. - * @param invalidKey the invalid key - * @param format the format the key should have been in - */ - public BadlyFormattedFlowExecutionKeyException(String invalidKey, String format) { - super("Badly formatted flow execution key '" + invalidKey + "', the expected format is '" + format + "'"); - this.invalidKey = invalidKey; - this.format = format; - } - - /** - * Creates a bad execution key format exception. - * @param invalidKey the invalid key - * @param format the format the key should have been in - * @param cause the cause - */ - public BadlyFormattedFlowExecutionKeyException(String invalidKey, String format, Throwable cause) { - super("Badly formatted flow execution key '" + invalidKey + "', the expected format is '" + format + "'", cause); - this.invalidKey = invalidKey; - this.format = format; - } - - /** - * Returns the string key of the flow execution that could not be parsed. - */ - public String getInvalidKey() { - return invalidKey; - } - - /** - * Returns the format the key should have been in. - */ - public String getFormat() { - return format; - } +/* + * 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 + * + * https://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; + +/** + * Thrown when an encoded flow execution key is badly formatted and could not be parsed. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class BadlyFormattedFlowExecutionKeyException extends FlowExecutionRepositoryException { + + /** + * The string encoded flow execution key that was invalid. + */ + private String invalidKey; + + /** + * The format the string key should have been in. Could just be a description of that format. + */ + private String format; + + /** + * Creates a bad execution key format exception. + * @param invalidKey the invalid key + * @param format the format the key should have been in + */ + public BadlyFormattedFlowExecutionKeyException(String invalidKey, String format) { + super("Badly formatted flow execution key '" + invalidKey + "', the expected format is '" + format + "'"); + this.invalidKey = invalidKey; + this.format = format; + } + + /** + * Creates a bad execution key format exception. + * @param invalidKey the invalid key + * @param format the format the key should have been in + * @param cause the cause + */ + public BadlyFormattedFlowExecutionKeyException(String invalidKey, String format, Throwable cause) { + super("Badly formatted flow execution key '" + invalidKey + "', the expected format is '" + format + "'", cause); + this.invalidKey = invalidKey; + this.format = format; + } + + /** + * Returns the string key of the flow execution that could not be parsed. + */ + public String getInvalidKey() { + return invalidKey; + } + + /** + * Returns the format the key should have been in. + */ + public String getFormat() { + return format; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/FlowExecutionAccessException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/FlowExecutionAccessException.java index d5509454..31412e4a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/FlowExecutionAccessException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/FlowExecutionAccessException.java @@ -1,59 +1,59 @@ -/* - * 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 - * - * https://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; - -import org.springframework.webflow.execution.FlowExecutionKey; - -/** - * Base class for exceptions that indicate a flow execution could not be accessed within a repository. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public abstract class FlowExecutionAccessException extends FlowExecutionRepositoryException { - - /** - * The key of the execution that could not be accessed. - */ - private FlowExecutionKey flowExecutionKey; - - /** - * Creates a new flow execution access exception. - * @param flowExecutionKey the key of the execution that could not be accessed - * @param message a descriptive message - */ - public FlowExecutionAccessException(FlowExecutionKey flowExecutionKey, String message) { - this(flowExecutionKey, message, null); - } - - /** - * Creates a new flow execution access exception. - * @param flowExecutionKey the key of the execution that could not be accessed - * @param message a descriptive message - * @param cause the root cause of the access failure - */ - public FlowExecutionAccessException(FlowExecutionKey flowExecutionKey, String message, Exception cause) { - super(message, cause); - this.flowExecutionKey = flowExecutionKey; - } - - /** - * Returns key of the flow execution that could not be accessed. - */ - public FlowExecutionKey getFlowExecutionKey() { - return flowExecutionKey; - } +/* + * 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 + * + * https://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; + +import org.springframework.webflow.execution.FlowExecutionKey; + +/** + * Base class for exceptions that indicate a flow execution could not be accessed within a repository. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public abstract class FlowExecutionAccessException extends FlowExecutionRepositoryException { + + /** + * The key of the execution that could not be accessed. + */ + private FlowExecutionKey flowExecutionKey; + + /** + * Creates a new flow execution access exception. + * @param flowExecutionKey the key of the execution that could not be accessed + * @param message a descriptive message + */ + public FlowExecutionAccessException(FlowExecutionKey flowExecutionKey, String message) { + this(flowExecutionKey, message, null); + } + + /** + * Creates a new flow execution access exception. + * @param flowExecutionKey the key of the execution that could not be accessed + * @param message a descriptive message + * @param cause the root cause of the access failure + */ + public FlowExecutionAccessException(FlowExecutionKey flowExecutionKey, String message, Exception cause) { + super(message, cause); + this.flowExecutionKey = flowExecutionKey; + } + + /** + * Returns key of the flow execution that could not be accessed. + */ + public FlowExecutionKey getFlowExecutionKey() { + return flowExecutionKey; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/FlowExecutionRestorationFailureException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/FlowExecutionRestorationFailureException.java index 2d2a5e3f..14ab03ac 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/FlowExecutionRestorationFailureException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/FlowExecutionRestorationFailureException.java @@ -1,37 +1,37 @@ -/* - * 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 - * - * https://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; - -import org.springframework.webflow.execution.FlowExecutionKey; - -/** - * Thrown when the flow execution with the persistent identifier provided could not be restored. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class FlowExecutionRestorationFailureException extends FlowExecutionAccessException { - - /** - * Creates a new flow execution restoration failure exception. - * @param flowExecutionKey the key of the execution that could not be restored - * @param cause the root cause of the restoration failure - */ - public FlowExecutionRestorationFailureException(FlowExecutionKey flowExecutionKey, Exception cause) { - super(flowExecutionKey, "A problem occurred restoring the flow execution with key '" + flowExecutionKey + "'", - cause); - } +/* + * 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 + * + * https://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; + +import org.springframework.webflow.execution.FlowExecutionKey; + +/** + * Thrown when the flow execution with the persistent identifier provided could not be restored. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class FlowExecutionRestorationFailureException extends FlowExecutionAccessException { + + /** + * Creates a new flow execution restoration failure exception. + * @param flowExecutionKey the key of the execution that could not be restored + * @param cause the root cause of the restoration failure + */ + public FlowExecutionRestorationFailureException(FlowExecutionKey flowExecutionKey, Exception cause) { + super(flowExecutionKey, "A problem occurred restoring the flow execution with key '" + flowExecutionKey + "'", + cause); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/PermissionDeniedFlowExecutionAccessException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/PermissionDeniedFlowExecutionAccessException.java index b6155ee7..55abdd83 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/PermissionDeniedFlowExecutionAccessException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/PermissionDeniedFlowExecutionAccessException.java @@ -1,37 +1,37 @@ -/* - * 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 - * - * https://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; - -import org.springframework.webflow.execution.FlowExecutionKey; - -/** - * Thrown when access to a flow execution was denied by a repository. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public class PermissionDeniedFlowExecutionAccessException extends FlowExecutionAccessException { - - /** - * Creates a new flow execution restoration exception. - * @param flowExecutionKey the key of the execution that could not be accessed - * @param cause the root cause of the access failure - */ - public PermissionDeniedFlowExecutionAccessException(FlowExecutionKey flowExecutionKey, Exception cause) { - super(flowExecutionKey, "Unable to restore flow execution with key '" + flowExecutionKey - + "' -- permission denied.", cause); - } +/* + * 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 + * + * https://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; + +import org.springframework.webflow.execution.FlowExecutionKey; + +/** + * Thrown when access to a flow execution was denied by a repository. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public class PermissionDeniedFlowExecutionAccessException extends FlowExecutionAccessException { + + /** + * Creates a new flow execution restoration exception. + * @param flowExecutionKey the key of the execution that could not be accessed + * @param cause the root cause of the access failure + */ + public PermissionDeniedFlowExecutionAccessException(FlowExecutionKey flowExecutionKey, Exception cause) { + super(flowExecutionKey, "Unable to restore flow execution with key '" + flowExecutionKey + + "' -- permission denied.", cause); + } } \ 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 index 1f92a7f7..a2b669b5 100644 --- 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 @@ -1,130 +1,130 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.snapshot.FlowExecutionSnapshot; -import org.springframework.webflow.execution.repository.snapshot.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. -1 indicates no max limit. - */ - private int maxSnapshots = -1; - - /** - * The snapshot id sequence ensuring unique snapshot ids within this group; snapshot ids start at 1. - */ - private int snapshotIdSequence = 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 = 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) { - if (!snapshots.containsKey(snapshotId)) { - return; - } - 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(); - } - - public Serializable nextSnapshotId() { - Integer nextSnapshotId = snapshotIdSequence; - snapshotIdSequence++; - return nextSnapshotId; - } - - /** - * 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()); - } - -} +/* + * Copyright 2004-2012 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 + * + * https://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.snapshot.FlowExecutionSnapshot; +import org.springframework.webflow.execution.repository.snapshot.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. -1 indicates no max limit. + */ + private int maxSnapshots = -1; + + /** + * The snapshot id sequence ensuring unique snapshot ids within this group; snapshot ids start at 1. + */ + private int snapshotIdSequence = 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 = 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) { + if (!snapshots.containsKey(snapshotId)) { + return; + } + 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(); + } + + public Serializable nextSnapshotId() { + Integer nextSnapshotId = snapshotIdSequence; + snapshotIdSequence++; + return nextSnapshotId; + } + + /** + * 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()); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotCreationException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotCreationException.java index 75d4c653..896bf63a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotCreationException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotCreationException.java @@ -1,50 +1,50 @@ -/* - * 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 - * - * https://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.snapshot; - -import org.springframework.webflow.execution.FlowExecution; -import org.springframework.webflow.execution.repository.FlowExecutionRepositoryException; - -/** - * Thrown when a continuation snapshot could not be taken of flow execution state. - * - * @author Keith Donald - */ -public class SnapshotCreationException extends FlowExecutionRepositoryException { - - /** - * The flow execution that could not be snapshotted. - */ - private FlowExecution flowExecution; - - /** - * Creates a new snapshot creation exception. - * @param flowExecution the flow execution - * @param message a descriptive message - * @param cause the cause - */ - public SnapshotCreationException(FlowExecution flowExecution, String message, Throwable cause) { - super(message, cause); - this.flowExecution = flowExecution; - } - - /** - * Returns the flow execution that could not be snapshotted. - */ - public FlowExecution getFlowExecution() { - return flowExecution; - } +/* + * 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 + * + * https://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.snapshot; + +import org.springframework.webflow.execution.FlowExecution; +import org.springframework.webflow.execution.repository.FlowExecutionRepositoryException; + +/** + * Thrown when a continuation snapshot could not be taken of flow execution state. + * + * @author Keith Donald + */ +public class SnapshotCreationException extends FlowExecutionRepositoryException { + + /** + * The flow execution that could not be snapshotted. + */ + private FlowExecution flowExecution; + + /** + * Creates a new snapshot creation exception. + * @param flowExecution the flow execution + * @param message a descriptive message + * @param cause the cause + */ + public SnapshotCreationException(FlowExecution flowExecution, String message, Throwable cause) { + super(message, cause); + this.flowExecution = flowExecution; + } + + /** + * Returns the flow execution that could not be snapshotted. + */ + public FlowExecution getFlowExecution() { + return flowExecution; + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotNotFoundException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotNotFoundException.java index 7f3fff31..750815f2 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotNotFoundException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotNotFoundException.java @@ -1,49 +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 - * - * https://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.snapshot; - -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; - } +/* + * 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 + * + * https://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.snapshot; + +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/snapshot/SnapshotUnmarshalException.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotUnmarshalException.java index 2c47aa7a..f34af13c 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotUnmarshalException.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/snapshot/SnapshotUnmarshalException.java @@ -1,39 +1,39 @@ -/* - * 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 - * - * https://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.snapshot; - -import org.springframework.webflow.execution.FlowExecution; -import org.springframework.webflow.execution.repository.FlowExecutionRepositoryException; - -/** - * Thrown when a FlowExecutionContinuation could not be deserialized into a FlowExecution. - * - * @see FlowExecutionSnapshot - * @see FlowExecution - * - * @author Keith Donald - */ -public class SnapshotUnmarshalException extends FlowExecutionRepositoryException { - - /** - * Creates a new flow execution unmarshalling exception. - * @param message the exception message - * @param cause the cause - */ - public SnapshotUnmarshalException(String message, Throwable cause) { - super(message, cause); - } +/* + * 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 + * + * https://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.snapshot; + +import org.springframework.webflow.execution.FlowExecution; +import org.springframework.webflow.execution.repository.FlowExecutionRepositoryException; + +/** + * Thrown when a FlowExecutionContinuation could not be deserialized into a FlowExecution. + * + * @see FlowExecutionSnapshot + * @see FlowExecution + * + * @author Keith Donald + */ +public class SnapshotUnmarshalException extends FlowExecutionRepositoryException { + + /** + * Creates a new flow execution unmarshalling exception. + * @param message the exception message + * @param cause the 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/support/AbstractFlowExecutionRepository.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/AbstractFlowExecutionRepository.java index b42cf3c8..822b2170 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 @@ -1,231 +1,231 @@ -/* - * 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 - * - * https://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.support; - -import java.io.Serializable; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; -import org.springframework.webflow.conversation.Conversation; -import org.springframework.webflow.conversation.ConversationException; -import org.springframework.webflow.conversation.ConversationId; -import org.springframework.webflow.conversation.ConversationManager; -import org.springframework.webflow.conversation.ConversationParameters; -import org.springframework.webflow.conversation.NoSuchConversationException; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.execution.FlowExecution; -import org.springframework.webflow.execution.FlowExecutionFactory; -import org.springframework.webflow.execution.FlowExecutionKey; -import org.springframework.webflow.execution.FlowExecutionKeyFactory; -import org.springframework.webflow.execution.repository.BadlyFormattedFlowExecutionKeyException; -import org.springframework.webflow.execution.repository.FlowExecutionLock; -import org.springframework.webflow.execution.repository.FlowExecutionRepository; -import org.springframework.webflow.execution.repository.FlowExecutionRepositoryException; -import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException; - -/** - * Abstract base class for flow execution repository implementations. Does not make any assumptions about the storage - * medium used to store active flow executions. Mandates the use of a {@link FlowExecutionStateRestorer}, used to - * 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 its {@link FlowExecutionFactory}. - * - * @author Keith Donald - * @author Erwin Vervaet - */ -public abstract class AbstractFlowExecutionRepository implements FlowExecutionRepository, FlowExecutionKeyFactory { - - /** - * Logger, usable in subclasses - */ - protected final Log logger = LogFactory.getLog(getClass()); - - private ConversationManager conversationManager; - - private boolean alwaysGenerateNewNextKey = true; - - /** - * Constructor for use in subclasses. - * @param conversationManager the conversation manager to use - */ - protected AbstractFlowExecutionRepository(ConversationManager conversationManager) { - Assert.notNull(conversationManager, "The conversation manager is required"); - this.conversationManager = conversationManager; - } - - /** - * The conversation service to delegate to for managing conversations initiated by this repository. - */ - public ConversationManager getConversationManager() { - return conversationManager; - } - - /** - * The flag indicating if a new {@link FlowExecutionKey} should always be generated before each put call. - */ - public boolean getAlwaysGenerateNewNextKey() { - return alwaysGenerateNewNextKey; - } - - /** - * Sets the flag indicating if a new {@link FlowExecutionKey} should always be generated before each put call. By - * setting this to false a FlowExecution can remain identified by the same key throughout its life. - */ - public void setAlwaysGenerateNewNextKey(boolean alwaysGenerateNewNextKey) { - this.alwaysGenerateNewNextKey = alwaysGenerateNewNextKey; - } - - // implementing flow execution key factory - - public FlowExecutionKey getKey(FlowExecution execution) { - CompositeFlowExecutionKey key = (CompositeFlowExecutionKey) execution.getKey(); - if (key == null) { - Conversation conversation = beginConversation(execution); - ConversationId executionId = conversation.getId(); - return new CompositeFlowExecutionKey(executionId, nextSnapshotId(executionId)); - } else { - if (alwaysGenerateNewNextKey) { - return new CompositeFlowExecutionKey(key.getExecutionId(), nextSnapshotId(key.getExecutionId())); - } else { - return execution.getKey(); - } - } - } - - // implementing flow execution repository - - public FlowExecutionKey parseFlowExecutionKey(String encodedKey) throws FlowExecutionRepositoryException { - if (!StringUtils.hasText(encodedKey)) { - throw new BadlyFormattedFlowExecutionKeyException(encodedKey, - "The string-encoded flow execution key is required"); - } - String[] keyParts = CompositeFlowExecutionKey.keyParts(encodedKey); - Serializable executionId = parseExecutionId(keyParts[0], encodedKey); - Serializable snapshotId = parseSnapshotId(keyParts[1], encodedKey); - return new CompositeFlowExecutionKey(executionId, snapshotId); - } - - public FlowExecutionLock getLock(FlowExecutionKey key) throws FlowExecutionRepositoryException { - return new ConversationBackedFlowExecutionLock(getConversation(key)); - } - - public void removeFlowExecution(FlowExecution flowExecution) throws FlowExecutionRepositoryException { - assertKeySet(flowExecution); - if (logger.isDebugEnabled()) { - logger.debug("Removing flow execution '" + flowExecution + "' from repository"); - } - endConversation(flowExecution); - } - - // abstract repository methods to be overridden by subclasses - - /** - * The next snapshot id to use for a {@link FlowExecution} instance. Called when {@link #getKey(FlowExecution) - * getting a flow execution key}. - * @return the id of the flow execution - */ - protected abstract Serializable nextSnapshotId(Serializable executionId); - - public abstract FlowExecution getFlowExecution(FlowExecutionKey key) throws FlowExecutionRepositoryException; - - public abstract void putFlowExecution(FlowExecution flowExecution) throws FlowExecutionRepositoryException; - - // hooks for use in subclasses - - /** - * Factory method that maps a new flow execution to a descriptive {@link ConversationParameters conversation - * parameters} object. - * @param flowExecution the new flow execution - * @return the conversation parameters object to pass to the conversation manager when the conversation is started - */ - protected ConversationParameters createConversationParameters(FlowExecution flowExecution) { - FlowDefinition flow = flowExecution.getDefinition(); - return new ConversationParameters(flow.getId(), flow.getCaption(), flow.getDescription()); - } - - /** - * Returns the conversation governing the {@link FlowExecution} with the provided key. - * @param key the flow execution key - * @return the governing conversation - * @throws NoSuchFlowExecutionException when the conversation for identified flow execution cannot be found - */ - protected Conversation getConversation(FlowExecutionKey key) throws NoSuchFlowExecutionException { - try { - return getConversation(((CompositeFlowExecutionKey) key).getExecutionId()); - } catch (NoSuchConversationException e) { - throw new NoSuchFlowExecutionException(key, e); - } - } - - /** - * Returns the conversation governing the logical flow execution with the given execution id. - * @param executionId the flow execution id - * @return the governing conversation - * @throws NoSuchConversationException when the conversation for identified flow execution cannot be found - */ - protected Conversation getConversation(Serializable executionId) throws NoSuchConversationException { - return conversationManager.getConversation((ConversationId) executionId); - } - - /** - * Assert that a flow execution key has been assigned to the execution. - * @param execution the flow execution - * @throws IllegalStateException if a key has not yet been assigned as expected - */ - protected void assertKeySet(FlowExecution execution) throws IllegalStateException { - if (execution.getKey() == null) { - throw new IllegalStateException( - "The key for the flow execution is null; make sure the key is assigned first. Execution Details = " - + execution); - } - } - - // internal helpers - - private Conversation beginConversation(FlowExecution execution) { - ConversationParameters parameters = createConversationParameters(execution); - Conversation conversation = conversationManager.beginConversation(parameters); - return conversation; - } - - 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) { - throw new BadlyFormattedFlowExecutionKeyException(encodedKey, CompositeFlowExecutionKey.getFormat(), e); - } - } - - private Conversation endConversation(FlowExecution flowExecution) { - Conversation conversation = getConversation(flowExecution.getKey()); - conversation.end(); - return conversation; - } - +/* + * 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 + * + * https://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.support; + +import java.io.Serializable; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.webflow.conversation.Conversation; +import org.springframework.webflow.conversation.ConversationException; +import org.springframework.webflow.conversation.ConversationId; +import org.springframework.webflow.conversation.ConversationManager; +import org.springframework.webflow.conversation.ConversationParameters; +import org.springframework.webflow.conversation.NoSuchConversationException; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.execution.FlowExecution; +import org.springframework.webflow.execution.FlowExecutionFactory; +import org.springframework.webflow.execution.FlowExecutionKey; +import org.springframework.webflow.execution.FlowExecutionKeyFactory; +import org.springframework.webflow.execution.repository.BadlyFormattedFlowExecutionKeyException; +import org.springframework.webflow.execution.repository.FlowExecutionLock; +import org.springframework.webflow.execution.repository.FlowExecutionRepository; +import org.springframework.webflow.execution.repository.FlowExecutionRepositoryException; +import org.springframework.webflow.execution.repository.NoSuchFlowExecutionException; + +/** + * Abstract base class for flow execution repository implementations. Does not make any assumptions about the storage + * medium used to store active flow executions. Mandates the use of a {@link FlowExecutionStateRestorer}, used to + * 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 its {@link FlowExecutionFactory}. + * + * @author Keith Donald + * @author Erwin Vervaet + */ +public abstract class AbstractFlowExecutionRepository implements FlowExecutionRepository, FlowExecutionKeyFactory { + + /** + * Logger, usable in subclasses + */ + protected final Log logger = LogFactory.getLog(getClass()); + + private ConversationManager conversationManager; + + private boolean alwaysGenerateNewNextKey = true; + + /** + * Constructor for use in subclasses. + * @param conversationManager the conversation manager to use + */ + protected AbstractFlowExecutionRepository(ConversationManager conversationManager) { + Assert.notNull(conversationManager, "The conversation manager is required"); + this.conversationManager = conversationManager; + } + + /** + * The conversation service to delegate to for managing conversations initiated by this repository. + */ + public ConversationManager getConversationManager() { + return conversationManager; + } + + /** + * The flag indicating if a new {@link FlowExecutionKey} should always be generated before each put call. + */ + public boolean getAlwaysGenerateNewNextKey() { + return alwaysGenerateNewNextKey; + } + + /** + * Sets the flag indicating if a new {@link FlowExecutionKey} should always be generated before each put call. By + * setting this to false a FlowExecution can remain identified by the same key throughout its life. + */ + public void setAlwaysGenerateNewNextKey(boolean alwaysGenerateNewNextKey) { + this.alwaysGenerateNewNextKey = alwaysGenerateNewNextKey; + } + + // implementing flow execution key factory + + public FlowExecutionKey getKey(FlowExecution execution) { + CompositeFlowExecutionKey key = (CompositeFlowExecutionKey) execution.getKey(); + if (key == null) { + Conversation conversation = beginConversation(execution); + ConversationId executionId = conversation.getId(); + return new CompositeFlowExecutionKey(executionId, nextSnapshotId(executionId)); + } else { + if (alwaysGenerateNewNextKey) { + return new CompositeFlowExecutionKey(key.getExecutionId(), nextSnapshotId(key.getExecutionId())); + } else { + return execution.getKey(); + } + } + } + + // implementing flow execution repository + + public FlowExecutionKey parseFlowExecutionKey(String encodedKey) throws FlowExecutionRepositoryException { + if (!StringUtils.hasText(encodedKey)) { + throw new BadlyFormattedFlowExecutionKeyException(encodedKey, + "The string-encoded flow execution key is required"); + } + String[] keyParts = CompositeFlowExecutionKey.keyParts(encodedKey); + Serializable executionId = parseExecutionId(keyParts[0], encodedKey); + Serializable snapshotId = parseSnapshotId(keyParts[1], encodedKey); + return new CompositeFlowExecutionKey(executionId, snapshotId); + } + + public FlowExecutionLock getLock(FlowExecutionKey key) throws FlowExecutionRepositoryException { + return new ConversationBackedFlowExecutionLock(getConversation(key)); + } + + public void removeFlowExecution(FlowExecution flowExecution) throws FlowExecutionRepositoryException { + assertKeySet(flowExecution); + if (logger.isDebugEnabled()) { + logger.debug("Removing flow execution '" + flowExecution + "' from repository"); + } + endConversation(flowExecution); + } + + // abstract repository methods to be overridden by subclasses + + /** + * The next snapshot id to use for a {@link FlowExecution} instance. Called when {@link #getKey(FlowExecution) + * getting a flow execution key}. + * @return the id of the flow execution + */ + protected abstract Serializable nextSnapshotId(Serializable executionId); + + public abstract FlowExecution getFlowExecution(FlowExecutionKey key) throws FlowExecutionRepositoryException; + + public abstract void putFlowExecution(FlowExecution flowExecution) throws FlowExecutionRepositoryException; + + // hooks for use in subclasses + + /** + * Factory method that maps a new flow execution to a descriptive {@link ConversationParameters conversation + * parameters} object. + * @param flowExecution the new flow execution + * @return the conversation parameters object to pass to the conversation manager when the conversation is started + */ + protected ConversationParameters createConversationParameters(FlowExecution flowExecution) { + FlowDefinition flow = flowExecution.getDefinition(); + return new ConversationParameters(flow.getId(), flow.getCaption(), flow.getDescription()); + } + + /** + * Returns the conversation governing the {@link FlowExecution} with the provided key. + * @param key the flow execution key + * @return the governing conversation + * @throws NoSuchFlowExecutionException when the conversation for identified flow execution cannot be found + */ + protected Conversation getConversation(FlowExecutionKey key) throws NoSuchFlowExecutionException { + try { + return getConversation(((CompositeFlowExecutionKey) key).getExecutionId()); + } catch (NoSuchConversationException e) { + throw new NoSuchFlowExecutionException(key, e); + } + } + + /** + * Returns the conversation governing the logical flow execution with the given execution id. + * @param executionId the flow execution id + * @return the governing conversation + * @throws NoSuchConversationException when the conversation for identified flow execution cannot be found + */ + protected Conversation getConversation(Serializable executionId) throws NoSuchConversationException { + return conversationManager.getConversation((ConversationId) executionId); + } + + /** + * Assert that a flow execution key has been assigned to the execution. + * @param execution the flow execution + * @throws IllegalStateException if a key has not yet been assigned as expected + */ + protected void assertKeySet(FlowExecution execution) throws IllegalStateException { + if (execution.getKey() == null) { + throw new IllegalStateException( + "The key for the flow execution is null; make sure the key is assigned first. Execution Details = " + + execution); + } + } + + // internal helpers + + private Conversation beginConversation(FlowExecution execution) { + ConversationParameters parameters = createConversationParameters(execution); + Conversation conversation = conversationManager.beginConversation(parameters); + return conversation; + } + + 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) { + throw new BadlyFormattedFlowExecutionKeyException(encodedKey, CompositeFlowExecutionKey.getFormat(), e); + } + } + + private Conversation endConversation(FlowExecution flowExecution) { + Conversation conversation = getConversation(flowExecution.getKey()); + conversation.end(); + return conversation; + } + } \ No newline at end of file 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 9aa1c5a4..7ef008ef 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 @@ -1,115 +1,115 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.support; - -import java.io.Serializable; - -import org.springframework.util.Assert; -import org.springframework.webflow.execution.FlowExecution; -import org.springframework.webflow.execution.FlowExecutionKey; -import org.springframework.webflow.execution.repository.BadlyFormattedFlowExecutionKeyException; - -/** - * A flow execution key that consists of two parts: - *

    - *
  1. A executionId, identifying a logical {@link FlowExecution} that is running. - *
  2. A snapshotId, identifying a physical flow execution snapshot that can be restored. - *
- * @author Keith Donald - */ -public class CompositeFlowExecutionKey extends FlowExecutionKey { - - private static final String EXECUTION_ID_PREFIX = "e"; - - private static final String SNAPSHOT_ID_PREFIX = "s"; - - private static final String FORMAT = EXECUTION_ID_PREFIX + "" + SNAPSHOT_ID_PREFIX + ""; - - private Serializable executionId; - - private Serializable snapshotId; - - /** - * Create a new composite flow execution key given the composing parts. - * @param executionId the execution id - * @param snapshotId the snapshot id - */ - public CompositeFlowExecutionKey(Serializable executionId, Serializable snapshotId) { - Assert.notNull(executionId, "The execution id is required"); - Assert.notNull(snapshotId, "The snapshot id is required"); - this.executionId = executionId; - this.snapshotId = snapshotId; - } - - /** - * Returns the execution id part of this key. - */ - public Serializable getExecutionId() { - return executionId; - } - - /** - * Returns the snapshot id part of this key. - */ - public Serializable getSnapshotId() { - return snapshotId; - } - - public boolean equals(Object obj) { - if (!(obj instanceof CompositeFlowExecutionKey)) { - return false; - } - CompositeFlowExecutionKey other = (CompositeFlowExecutionKey) obj; - return executionId.equals(other.executionId) && snapshotId.equals(other.snapshotId); - } - - public int hashCode() { - return executionId.hashCode() + snapshotId.hashCode(); - } - - public String toString() { - return new StringBuilder().append(EXECUTION_ID_PREFIX).append(executionId).append(SNAPSHOT_ID_PREFIX) - .append(snapshotId).toString(); - } - - // static helpers - - /** - * Returns a string description of the format of this key. - */ - public static String getFormat() { - return FORMAT; - } - - /** - * Helper that splits the string-form of an instance of this class into its "parts" so the parts can be easily - * parsed. - * @param encodedKey the string-encoded composite flow execution key - * @return the composite key parts as a String array (executionId = 0, snapshotId = 1) - */ - public static String[] keyParts(String encodedKey) throws BadlyFormattedFlowExecutionKeyException { - if (!encodedKey.startsWith(EXECUTION_ID_PREFIX)) { - throw new BadlyFormattedFlowExecutionKeyException(encodedKey, FORMAT); - } - int snapshotStart = encodedKey.indexOf(SNAPSHOT_ID_PREFIX, EXECUTION_ID_PREFIX.length()); - if (snapshotStart == -1) { - throw new BadlyFormattedFlowExecutionKeyException(encodedKey, FORMAT); - } - String executionId = encodedKey.substring(EXECUTION_ID_PREFIX.length(), snapshotStart); - String snapshotId = encodedKey.substring(snapshotStart + SNAPSHOT_ID_PREFIX.length()); - return new String[] { executionId, snapshotId }; - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.support; + +import java.io.Serializable; + +import org.springframework.util.Assert; +import org.springframework.webflow.execution.FlowExecution; +import org.springframework.webflow.execution.FlowExecutionKey; +import org.springframework.webflow.execution.repository.BadlyFormattedFlowExecutionKeyException; + +/** + * A flow execution key that consists of two parts: + *
    + *
  1. A executionId, identifying a logical {@link FlowExecution} that is running. + *
  2. A snapshotId, identifying a physical flow execution snapshot that can be restored. + *
+ * @author Keith Donald + */ +public class CompositeFlowExecutionKey extends FlowExecutionKey { + + private static final String EXECUTION_ID_PREFIX = "e"; + + private static final String SNAPSHOT_ID_PREFIX = "s"; + + private static final String FORMAT = EXECUTION_ID_PREFIX + "" + SNAPSHOT_ID_PREFIX + ""; + + private Serializable executionId; + + private Serializable snapshotId; + + /** + * Create a new composite flow execution key given the composing parts. + * @param executionId the execution id + * @param snapshotId the snapshot id + */ + public CompositeFlowExecutionKey(Serializable executionId, Serializable snapshotId) { + Assert.notNull(executionId, "The execution id is required"); + Assert.notNull(snapshotId, "The snapshot id is required"); + this.executionId = executionId; + this.snapshotId = snapshotId; + } + + /** + * Returns the execution id part of this key. + */ + public Serializable getExecutionId() { + return executionId; + } + + /** + * Returns the snapshot id part of this key. + */ + public Serializable getSnapshotId() { + return snapshotId; + } + + public boolean equals(Object obj) { + if (!(obj instanceof CompositeFlowExecutionKey)) { + return false; + } + CompositeFlowExecutionKey other = (CompositeFlowExecutionKey) obj; + return executionId.equals(other.executionId) && snapshotId.equals(other.snapshotId); + } + + public int hashCode() { + return executionId.hashCode() + snapshotId.hashCode(); + } + + public String toString() { + return new StringBuilder().append(EXECUTION_ID_PREFIX).append(executionId).append(SNAPSHOT_ID_PREFIX) + .append(snapshotId).toString(); + } + + // static helpers + + /** + * Returns a string description of the format of this key. + */ + public static String getFormat() { + return FORMAT; + } + + /** + * Helper that splits the string-form of an instance of this class into its "parts" so the parts can be easily + * parsed. + * @param encodedKey the string-encoded composite flow execution key + * @return the composite key parts as a String array (executionId = 0, snapshotId = 1) + */ + public static String[] keyParts(String encodedKey) throws BadlyFormattedFlowExecutionKeyException { + if (!encodedKey.startsWith(EXECUTION_ID_PREFIX)) { + throw new BadlyFormattedFlowExecutionKeyException(encodedKey, FORMAT); + } + int snapshotStart = encodedKey.indexOf(SNAPSHOT_ID_PREFIX, EXECUTION_ID_PREFIX.length()); + if (snapshotStart == -1) { + throw new BadlyFormattedFlowExecutionKeyException(encodedKey, FORMAT); + } + String executionId = encodedKey.substring(EXECUTION_ID_PREFIX.length(), snapshotStart); + String snapshotId = encodedKey.substring(snapshotStart + SNAPSHOT_ID_PREFIX.length()); + return new String[] { executionId, snapshotId }; + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/ConversationBackedFlowExecutionLock.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/ConversationBackedFlowExecutionLock.java index a6f73fd4..29eade62 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/ConversationBackedFlowExecutionLock.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/ConversationBackedFlowExecutionLock.java @@ -1,57 +1,57 @@ -/* - * 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 - * - * https://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.support; - -import org.springframework.webflow.conversation.Conversation; -import org.springframework.webflow.conversation.ConversationManager; -import org.springframework.webflow.execution.repository.FlowExecutionLock; - -/** - * A flow execution lock that locks a conversation managed by a {@link ConversationManager}. - *

- * This implementation ensures multiple threads cannot manipulate the same conversation at the same time. The locked - * conversation is the sole gateway to a flow execution, and a lock on it prevents access to any associated execution. - * - * @see ConversationManager - * @see Conversation - * @see Conversation#lock() - * @see Conversation#unlock() - * - * @author Keith Donald - */ -class ConversationBackedFlowExecutionLock implements FlowExecutionLock { - - /** - * The conversation to lock. - */ - private Conversation conversation; - - /** - * Creates a new conversation-backed flow execution lock. - * @param conversation the conversation to lock - */ - public ConversationBackedFlowExecutionLock(Conversation conversation) { - this.conversation = conversation; - } - - public void lock() { - conversation.lock(); - } - - public void unlock() { - conversation.unlock(); - } +/* + * 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 + * + * https://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.support; + +import org.springframework.webflow.conversation.Conversation; +import org.springframework.webflow.conversation.ConversationManager; +import org.springframework.webflow.execution.repository.FlowExecutionLock; + +/** + * A flow execution lock that locks a conversation managed by a {@link ConversationManager}. + *

+ * This implementation ensures multiple threads cannot manipulate the same conversation at the same time. The locked + * conversation is the sole gateway to a flow execution, and a lock on it prevents access to any associated execution. + * + * @see ConversationManager + * @see Conversation + * @see Conversation#lock() + * @see Conversation#unlock() + * + * @author Keith Donald + */ +class ConversationBackedFlowExecutionLock implements FlowExecutionLock { + + /** + * The conversation to lock. + */ + private Conversation conversation; + + /** + * Creates a new conversation-backed flow execution lock. + * @param conversation the conversation to lock + */ + public ConversationBackedFlowExecutionLock(Conversation conversation) { + this.conversation = conversation; + } + + public void lock() { + conversation.lock(); + } + + public void unlock() { + conversation.unlock(); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/FlowExecutionStateRestorer.java b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/FlowExecutionStateRestorer.java index f9791c53..4cf5bf4e 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/FlowExecutionStateRestorer.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/execution/repository/support/FlowExecutionStateRestorer.java @@ -1,44 +1,44 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.support; - -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.registry.FlowDefinitionLocator; -import org.springframework.webflow.execution.FlowExecution; -import org.springframework.webflow.execution.FlowExecutionKey; - -/** - * A strategy used by repositories to restore transient flow execution state during execution restoration. - * - * @author Keith Donald - */ -public interface FlowExecutionStateRestorer { - - /** - * Restore the transient state of the flow execution. - * @param execution the flow execution, newly deserialized and needing restoration - * @param definition the root flow definition for the execution, typically not part of the serialized form - * @param key the flow execution key, typically not part of the serialized form - * @param conversationScope the execution's conversation scope, which is typically not part of the serialized form - * since it could be shared by multiple physical flow execution copies all sharing the same logical - * conversation - * @param subflowDefinitionLocator for locating the definitions of any subflows started by the execution - * @return the restored flow execution - */ - FlowExecution restoreState(FlowExecution execution, FlowDefinition definition, FlowExecutionKey key, - MutableAttributeMap conversationScope, FlowDefinitionLocator subflowDefinitionLocator); -} +/* + * Copyright 2004-2012 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 + * + * https://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.support; + +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.registry.FlowDefinitionLocator; +import org.springframework.webflow.execution.FlowExecution; +import org.springframework.webflow.execution.FlowExecutionKey; + +/** + * A strategy used by repositories to restore transient flow execution state during execution restoration. + * + * @author Keith Donald + */ +public interface FlowExecutionStateRestorer { + + /** + * Restore the transient state of the flow execution. + * @param execution the flow execution, newly deserialized and needing restoration + * @param definition the root flow definition for the execution, typically not part of the serialized form + * @param key the flow execution key, typically not part of the serialized form + * @param conversationScope the execution's conversation scope, which is typically not part of the serialized form + * since it could be shared by multiple physical flow execution copies all sharing the same logical + * conversation + * @param subflowDefinitionLocator for locating the definitions of any subflows started by the execution + * @return the restored flow execution + */ + FlowExecution restoreState(FlowExecution execution, FlowDefinition definition, FlowExecutionKey key, + MutableAttributeMap conversationScope, FlowDefinitionLocator subflowDefinitionLocator); +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/FlowExecutorImpl.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/FlowExecutorImpl.java index c140bcf5..e0a166ea 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/executor/FlowExecutorImpl.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/FlowExecutorImpl.java @@ -1,193 +1,193 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.executor; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.util.Assert; -import org.springframework.webflow.context.ExternalContext; -import org.springframework.webflow.context.ExternalContextHolder; -import org.springframework.webflow.core.FlowException; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.registry.FlowDefinitionLocator; -import org.springframework.webflow.execution.FlowExecution; -import org.springframework.webflow.execution.FlowExecutionFactory; -import org.springframework.webflow.execution.FlowExecutionKey; -import org.springframework.webflow.execution.repository.FlowExecutionLock; -import org.springframework.webflow.execution.repository.FlowExecutionRepository; - -/** - * The default implementation of the central facade for driving the execution of flows within an application. - *

- * This object is responsible for creating and launching new flow executions as requested by clients, as well as - * resuming existing, paused executions (that were waiting to be resumed in response to a user event). - *

- * This object is a facade or entry point into the Spring Web Flow execution system and makes the overall system easier - * to use. The name executor was chosen as executors drive executions. - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Commonly used configurable properties
namedescriptiondefault
definitionLocatorThe service locator responsible for loading flow definitions to execute.None
executionFactoryThe factory responsible for creating new flow executions.None
executionRepositoryThe repository responsible for managing flow execution persistence.None
- * - * @see FlowDefinitionLocator - * @see FlowExecutionFactory - * @see FlowExecutionRepository - * - * @author Keith Donald - * @author Erwin Vervaet - * @author Colin Sampaleanu - */ -public class FlowExecutorImpl implements FlowExecutor { - - private static final Log logger = LogFactory.getLog(FlowExecutorImpl.class); - - /** - * The locator to access flow definitions registered in a central registry. - */ - private FlowDefinitionLocator definitionLocator; - - /** - * The abstract factory for creating a new execution of a flow definition. - */ - private FlowExecutionFactory executionFactory; - - /** - * The repository used to save, update, and load existing flow executions to/from a persistent store. - */ - private FlowExecutionRepository executionRepository; - - /** - * Create a new flow executor. - * @param definitionLocator the locator for accessing flow definitions to execute - * @param executionFactory the factory for creating executions of flow definitions - * @param executionRepository the repository for persisting paused flow executions - */ - public FlowExecutorImpl(FlowDefinitionLocator definitionLocator, FlowExecutionFactory executionFactory, - FlowExecutionRepository executionRepository) { - Assert.notNull(definitionLocator, "The locator for accessing flow definitions is required"); - Assert.notNull(executionFactory, "The execution factory for creating new flow executions is required"); - Assert.notNull(executionRepository, "The repository for persisting flow executions is required"); - this.definitionLocator = definitionLocator; - this.executionFactory = executionFactory; - this.executionRepository = executionRepository; - } - - /** - * Returns the locator to load flow definitions to execute. - */ - public FlowDefinitionLocator getDefinitionLocator() { - return definitionLocator; - } - - /** - * Returns the abstract factory used to create new executions of a flow. - */ - public FlowExecutionFactory getExecutionFactory() { - return executionFactory; - } - - /** - * Returns the repository used to save, update, and load existing flow executions to/from a persistent store. - */ - public FlowExecutionRepository getExecutionRepository() { - return executionRepository; - } - - public FlowExecutionResult launchExecution(String flowId, MutableAttributeMap input, ExternalContext context) - throws FlowException { - try { - if (logger.isDebugEnabled()) { - logger.debug("Launching new execution of flow '" + flowId + "' with input " + input); - } - ExternalContextHolder.setExternalContext(context); - FlowDefinition flowDefinition = definitionLocator.getFlowDefinition(flowId); - FlowExecution flowExecution = executionFactory.createFlowExecution(flowDefinition); - flowExecution.start(input, context); - if (!flowExecution.hasEnded()) { - FlowExecutionLock lock = executionRepository.getLock(flowExecution.getKey()); - lock.lock(); - try { - executionRepository.putFlowExecution(flowExecution); - } finally { - lock.unlock(); - } - return createPausedResult(flowExecution); - } else { - return createEndResult(flowExecution); - } - } finally { - ExternalContextHolder.setExternalContext(null); - } - } - - public FlowExecutionResult resumeExecution(String flowExecutionKey, ExternalContext context) throws FlowException { - try { - if (logger.isDebugEnabled()) { - logger.debug("Resuming flow execution with key '" + flowExecutionKey); - } - ExternalContextHolder.setExternalContext(context); - FlowExecutionKey key = executionRepository.parseFlowExecutionKey(flowExecutionKey); - FlowExecutionLock lock = executionRepository.getLock(key); - lock.lock(); - try { - FlowExecution flowExecution = executionRepository.getFlowExecution(key); - flowExecution.resume(context); - if (!flowExecution.hasEnded()) { - executionRepository.putFlowExecution(flowExecution); - return createPausedResult(flowExecution); - } else { - executionRepository.removeFlowExecution(flowExecution); - return createEndResult(flowExecution); - } - } finally { - lock.unlock(); - } - } finally { - ExternalContextHolder.setExternalContext(null); - } - } - - private FlowExecutionResult createEndResult(FlowExecution flowExecution) { - return FlowExecutionResult.createEndedResult(flowExecution.getDefinition().getId(), flowExecution.getOutcome()); - } - - private FlowExecutionResult createPausedResult(FlowExecution flowExecution) { - return FlowExecutionResult.createPausedResult(flowExecution.getDefinition().getId(), flowExecution.getKey() - .toString()); - } - -} +/* + * Copyright 2004-2012 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 + * + * https://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.executor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.util.Assert; +import org.springframework.webflow.context.ExternalContext; +import org.springframework.webflow.context.ExternalContextHolder; +import org.springframework.webflow.core.FlowException; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.registry.FlowDefinitionLocator; +import org.springframework.webflow.execution.FlowExecution; +import org.springframework.webflow.execution.FlowExecutionFactory; +import org.springframework.webflow.execution.FlowExecutionKey; +import org.springframework.webflow.execution.repository.FlowExecutionLock; +import org.springframework.webflow.execution.repository.FlowExecutionRepository; + +/** + * The default implementation of the central facade for driving the execution of flows within an application. + *

+ * This object is responsible for creating and launching new flow executions as requested by clients, as well as + * resuming existing, paused executions (that were waiting to be resumed in response to a user event). + *

+ * This object is a facade or entry point into the Spring Web Flow execution system and makes the overall system easier + * to use. The name executor was chosen as executors drive executions. + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Commonly used configurable properties
namedescriptiondefault
definitionLocatorThe service locator responsible for loading flow definitions to execute.None
executionFactoryThe factory responsible for creating new flow executions.None
executionRepositoryThe repository responsible for managing flow execution persistence.None
+ * + * @see FlowDefinitionLocator + * @see FlowExecutionFactory + * @see FlowExecutionRepository + * + * @author Keith Donald + * @author Erwin Vervaet + * @author Colin Sampaleanu + */ +public class FlowExecutorImpl implements FlowExecutor { + + private static final Log logger = LogFactory.getLog(FlowExecutorImpl.class); + + /** + * The locator to access flow definitions registered in a central registry. + */ + private FlowDefinitionLocator definitionLocator; + + /** + * The abstract factory for creating a new execution of a flow definition. + */ + private FlowExecutionFactory executionFactory; + + /** + * The repository used to save, update, and load existing flow executions to/from a persistent store. + */ + private FlowExecutionRepository executionRepository; + + /** + * Create a new flow executor. + * @param definitionLocator the locator for accessing flow definitions to execute + * @param executionFactory the factory for creating executions of flow definitions + * @param executionRepository the repository for persisting paused flow executions + */ + public FlowExecutorImpl(FlowDefinitionLocator definitionLocator, FlowExecutionFactory executionFactory, + FlowExecutionRepository executionRepository) { + Assert.notNull(definitionLocator, "The locator for accessing flow definitions is required"); + Assert.notNull(executionFactory, "The execution factory for creating new flow executions is required"); + Assert.notNull(executionRepository, "The repository for persisting flow executions is required"); + this.definitionLocator = definitionLocator; + this.executionFactory = executionFactory; + this.executionRepository = executionRepository; + } + + /** + * Returns the locator to load flow definitions to execute. + */ + public FlowDefinitionLocator getDefinitionLocator() { + return definitionLocator; + } + + /** + * Returns the abstract factory used to create new executions of a flow. + */ + public FlowExecutionFactory getExecutionFactory() { + return executionFactory; + } + + /** + * Returns the repository used to save, update, and load existing flow executions to/from a persistent store. + */ + public FlowExecutionRepository getExecutionRepository() { + return executionRepository; + } + + public FlowExecutionResult launchExecution(String flowId, MutableAttributeMap input, ExternalContext context) + throws FlowException { + try { + if (logger.isDebugEnabled()) { + logger.debug("Launching new execution of flow '" + flowId + "' with input " + input); + } + ExternalContextHolder.setExternalContext(context); + FlowDefinition flowDefinition = definitionLocator.getFlowDefinition(flowId); + FlowExecution flowExecution = executionFactory.createFlowExecution(flowDefinition); + flowExecution.start(input, context); + if (!flowExecution.hasEnded()) { + FlowExecutionLock lock = executionRepository.getLock(flowExecution.getKey()); + lock.lock(); + try { + executionRepository.putFlowExecution(flowExecution); + } finally { + lock.unlock(); + } + return createPausedResult(flowExecution); + } else { + return createEndResult(flowExecution); + } + } finally { + ExternalContextHolder.setExternalContext(null); + } + } + + public FlowExecutionResult resumeExecution(String flowExecutionKey, ExternalContext context) throws FlowException { + try { + if (logger.isDebugEnabled()) { + logger.debug("Resuming flow execution with key '" + flowExecutionKey); + } + ExternalContextHolder.setExternalContext(context); + FlowExecutionKey key = executionRepository.parseFlowExecutionKey(flowExecutionKey); + FlowExecutionLock lock = executionRepository.getLock(key); + lock.lock(); + try { + FlowExecution flowExecution = executionRepository.getFlowExecution(key); + flowExecution.resume(context); + if (!flowExecution.hasEnded()) { + executionRepository.putFlowExecution(flowExecution); + return createPausedResult(flowExecution); + } else { + executionRepository.removeFlowExecution(flowExecution); + return createEndResult(flowExecution); + } + } finally { + lock.unlock(); + } + } finally { + ExternalContextHolder.setExternalContext(null); + } + } + + private FlowExecutionResult createEndResult(FlowExecution flowExecution) { + return FlowExecutionResult.createEndedResult(flowExecution.getDefinition().getId(), flowExecution.getOutcome()); + } + + private FlowExecutionResult createPausedResult(FlowExecution flowExecution) { + return FlowExecutionResult.createPausedResult(flowExecution.getDefinition().getId(), flowExecution.getKey() + .toString()); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/BeanFactoryPropertyAccessor.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/BeanFactoryPropertyAccessor.java index f5abad6d..53700143 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/BeanFactoryPropertyAccessor.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/spel/BeanFactoryPropertyAccessor.java @@ -1,69 +1,69 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.expression.spel; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.support.StaticListableBeanFactory; -import org.springframework.expression.AccessException; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.PropertyAccessor; -import org.springframework.expression.TypedValue; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.RequestContextHolder; - -/** - * Spring EL PropertyAccessor for reading beans in a {@link org.springframework.beans.factory.BeanFactory}. - * - * @author Rossen Stoyanchev - * @since 2.1 - */ -public class BeanFactoryPropertyAccessor implements PropertyAccessor { - - private static final BeanFactory EMPTY_BEAN_FACTORY = new StaticListableBeanFactory(); - - public Class[] getSpecificTargetClasses() { - return null; - } - - public boolean canRead(EvaluationContext context, Object target, String name) { - return getBeanFactory().containsBean(name); - } - - public TypedValue read(EvaluationContext context, Object target, String name) { - return new TypedValue(getBeanFactory().getBean(name)); - } - - public boolean canWrite(EvaluationContext context, Object target, String name) { - return false; - } - - public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { - throw new AccessException("Beans in a BeanFactory are read-only"); - } - - protected BeanFactory getBeanFactory() { - RequestContext requestContext = RequestContextHolder.getRequestContext(); - if (requestContext != null) { - BeanFactory beanFactory = requestContext.getActiveFlow().getApplicationContext(); - if (beanFactory != null) { - return beanFactory; - } - } - return EMPTY_BEAN_FACTORY; - } - -} +/* + * Copyright 2004-2012 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 + * + * https://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.expression.spel; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.support.StaticListableBeanFactory; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.RequestContextHolder; + +/** + * Spring EL PropertyAccessor for reading beans in a {@link org.springframework.beans.factory.BeanFactory}. + * + * @author Rossen Stoyanchev + * @since 2.1 + */ +public class BeanFactoryPropertyAccessor implements PropertyAccessor { + + private static final BeanFactory EMPTY_BEAN_FACTORY = new StaticListableBeanFactory(); + + public Class[] getSpecificTargetClasses() { + return null; + } + + public boolean canRead(EvaluationContext context, Object target, String name) { + return getBeanFactory().containsBean(name); + } + + public TypedValue read(EvaluationContext context, Object target, String name) { + return new TypedValue(getBeanFactory().getBean(name)); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) { + return false; + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + throw new AccessException("Beans in a BeanFactory are read-only"); + } + + protected BeanFactory getBeanFactory() { + RequestContext requestContext = RequestContextHolder.getRequestContext(); + if (requestContext != null) { + BeanFactory beanFactory = requestContext.getActiveFlow().getApplicationContext(); + if (beanFactory != null) { + return beanFactory; + } + } + return EMPTY_BEAN_FACTORY; + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/action/EvaluateActionTests.java b/spring-webflow/src/test/java/org/springframework/webflow/action/EvaluateActionTests.java index f15cdc2a..b031cc82 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/action/EvaluateActionTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/action/EvaluateActionTests.java @@ -1,64 +1,64 @@ -/* - * 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 - * - * https://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.action; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; -import org.springframework.binding.expression.support.StaticExpression; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.test.MockRequestContext; - -/** - * Unit tests for {@link EvaluateAction}. - * @author Jeremy Grelle - */ -public class EvaluateActionTests { - +/* + * 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 + * + * https://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.action; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.springframework.binding.expression.support.StaticExpression; +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.test.MockRequestContext; + +/** + * Unit tests for {@link EvaluateAction}. + * @author Jeremy Grelle + */ +public class EvaluateActionTests { + @Test - public void testEvaluateExpressionNoResultExposer() throws Exception { - EvaluateAction action = new EvaluateAction(new StaticExpression("bar"), null); - MockRequestContext context = new MockRequestContext(); - Event result = action.execute(context); - assertEquals("bar", result.getId()); - } - + public void testEvaluateExpressionNoResultExposer() throws Exception { + EvaluateAction action = new EvaluateAction(new StaticExpression("bar"), null); + MockRequestContext context = new MockRequestContext(); + Event result = action.execute(context); + assertEquals("bar", result.getId()); + } + @Test - public void testEvaluateExpressionEmptyStringResult() throws Exception { - EvaluateAction action = new EvaluateAction(new StaticExpression(""), null); - MockRequestContext context = new MockRequestContext(); - Event result = action.execute(context); - assertEquals("null", result.getId()); - } - + public void testEvaluateExpressionEmptyStringResult() throws Exception { + EvaluateAction action = new EvaluateAction(new StaticExpression(""), null); + MockRequestContext context = new MockRequestContext(); + Event result = action.execute(context); + assertEquals("null", result.getId()); + } + @Test - public void testEvaluateExpressionNullResult() throws Exception { - EvaluateAction action = new EvaluateAction(new StaticExpression(null), null); - MockRequestContext context = new MockRequestContext(); - Event result = action.execute(context); - assertEquals("success", result.getId()); - } - + public void testEvaluateExpressionNullResult() throws Exception { + EvaluateAction action = new EvaluateAction(new StaticExpression(null), null); + MockRequestContext context = new MockRequestContext(); + Event result = action.execute(context); + assertEquals("success", result.getId()); + } + @Test - public void testEvaluateExpressionResultExposer() throws Exception { - StaticExpression resultExpression = new StaticExpression(""); - EvaluateAction action = new EvaluateAction(new StaticExpression("bar"), resultExpression); - MockRequestContext context = new MockRequestContext(); - Event result = action.execute(context); - assertEquals("bar", result.getId()); - assertEquals("bar", resultExpression.getValue(null)); - } + public void testEvaluateExpressionResultExposer() throws Exception { + StaticExpression resultExpression = new StaticExpression(""); + EvaluateAction action = new EvaluateAction(new StaticExpression("bar"), resultExpression); + MockRequestContext context = new MockRequestContext(); + Event result = action.execute(context); + assertEquals("bar", result.getId()); + assertEquals("bar", resultExpression.getValue(null)); + } } \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/action/EventFactorySupportTests.java b/spring-webflow/src/test/java/org/springframework/webflow/action/EventFactorySupportTests.java index a5a575f3..b700615a 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/action/EventFactorySupportTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/action/EventFactorySupportTests.java @@ -1,113 +1,113 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.action; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertSame; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.webflow.execution.Event; - -/** - * Unit tests for {@link EventFactorySupport}. - */ -public class EventFactorySupportTests { - - private EventFactorySupport support = new EventFactorySupport(); - - private Object source = new Object(); - +/* + * Copyright 2004-2012 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 + * + * https://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.action; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.webflow.execution.Event; + +/** + * Unit tests for {@link EventFactorySupport}. + */ +public class EventFactorySupportTests { + + private EventFactorySupport support = new EventFactorySupport(); + + private Object source = new Object(); + @BeforeEach - public void setUp() throws Exception { - } - + public void setUp() throws Exception { + } + @Test - public void testSuccess() { - Event e = support.success(source); - assertEquals("success", e.getId()); - assertSame(source, e.getSource()); - } - + public void testSuccess() { + Event e = support.success(source); + assertEquals("success", e.getId()); + assertSame(source, e.getSource()); + } + @Test - public void testSuccessWithResult() { - Object result = new Object(); - Event e = support.success(source, result); - assertEquals("success", e.getId()); - assertSame(source, e.getSource()); - assertSame(result, e.getAttributes().get("result")); - } - + public void testSuccessWithResult() { + Object result = new Object(); + Event e = support.success(source, result); + assertEquals("success", e.getId()); + assertSame(source, e.getSource()); + assertSame(result, e.getAttributes().get("result")); + } + @Test - public void testError() { - Event e = support.error(source); - assertEquals("error", e.getId()); - assertSame(source, e.getSource()); - } - + public void testError() { + Event e = support.error(source); + assertEquals("error", e.getId()); + assertSame(source, e.getSource()); + } + @Test - public void testErrorWithException() { - Exception ex = new Exception(); - Event e = support.error(source, ex); - assertEquals("error", e.getId()); - assertSame(source, e.getSource()); - assertSame(ex, e.getAttributes().get("exception")); - } - + public void testErrorWithException() { + Exception ex = new Exception(); + Event e = support.error(source, ex); + assertEquals("error", e.getId()); + assertSame(source, e.getSource()); + assertSame(ex, e.getAttributes().get("exception")); + } + @Test - public void testYes() { - Event e = support.yes(source); - assertEquals("yes", e.getId()); - assertSame(source, e.getSource()); - } - + public void testYes() { + Event e = support.yes(source); + assertEquals("yes", e.getId()); + assertSame(source, e.getSource()); + } + @Test - public void testNo() { - Event e = support.no(source); - assertEquals("no", e.getId()); - assertSame(source, e.getSource()); - } - + public void testNo() { + Event e = support.no(source); + assertEquals("no", e.getId()); + assertSame(source, e.getSource()); + } + @Test - public void testBooleanTrueEvent() { - Event e = support.event(source, true); - assertEquals("yes", e.getId()); - assertSame(source, e.getSource()); - } - + public void testBooleanTrueEvent() { + Event e = support.event(source, true); + assertEquals("yes", e.getId()); + assertSame(source, e.getSource()); + } + @Test - public void testBooleanFalseEvent() { - Event e = support.event(source, false); - assertEquals("no", e.getId()); - assertSame(source, e.getSource()); - } - + public void testBooleanFalseEvent() { + Event e = support.event(source, false); + assertEquals("no", e.getId()); + assertSame(source, e.getSource()); + } + @Test - public void testEvent() { - Event e = support.event(source, "no"); - assertEquals("no", e.getId()); - assertSame(source, e.getSource()); - } - + public void testEvent() { + Event e = support.event(source, "no"); + assertEquals("no", e.getId()); + assertSame(source, e.getSource()); + } + @Test - public void testEventWithAttrs() { - Event e = support.event(source, "no", "foo", "bar"); - assertEquals("no", e.getId()); - assertEquals("bar", e.getAttributes().get("foo")); - assertSame(source, e.getSource()); - } - + public void testEventWithAttrs() { + Event e = support.event(source, "no", "foo", "bar"); + assertEquals("no", e.getId()); + assertEquals("bar", e.getAttributes().get("foo")); + assertSame(source, e.getSource()); + } + } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/action/MultiActionTests.java b/spring-webflow/src/test/java/org/springframework/webflow/action/MultiActionTests.java index 221deb1e..8fa42413 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/action/MultiActionTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/action/MultiActionTests.java @@ -1,93 +1,93 @@ -/* - * 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 - * - * https://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.action; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; - -import org.junit.jupiter.api.Test; -import org.springframework.webflow.action.DispatchMethodInvoker.MethodLookupException; -import org.springframework.webflow.action.MultiAction.MethodResolver; -import org.springframework.webflow.engine.StubViewFactory; -import org.springframework.webflow.engine.ViewState; -import org.springframework.webflow.execution.AnnotatedAction; -import org.springframework.webflow.test.MockFlowSession; -import org.springframework.webflow.test.MockRequestContext; - -/** - * Unit tests for {@link MultiAction}. - */ -public class MultiActionTests { - - private TestMultiAction action = new TestMultiAction(); - - private MockRequestContext context = new MockRequestContext(); - +/* + * 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 + * + * https://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.action; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.Test; +import org.springframework.webflow.action.DispatchMethodInvoker.MethodLookupException; +import org.springframework.webflow.action.MultiAction.MethodResolver; +import org.springframework.webflow.engine.StubViewFactory; +import org.springframework.webflow.engine.ViewState; +import org.springframework.webflow.execution.AnnotatedAction; +import org.springframework.webflow.test.MockFlowSession; +import org.springframework.webflow.test.MockRequestContext; + +/** + * Unit tests for {@link MultiAction}. + */ +public class MultiActionTests { + + private TestMultiAction action = new TestMultiAction(); + + private MockRequestContext context = new MockRequestContext(); + @Test - public void testDispatchWithMethodSignature() throws Exception { - context.getAttributeMap().put(AnnotatedAction.METHOD_ATTRIBUTE, "increment"); - action.execute(context); - assertEquals(1, action.counter); - } - + public void testDispatchWithMethodSignature() throws Exception { + context.getAttributeMap().put(AnnotatedAction.METHOD_ATTRIBUTE, "increment"); + action.execute(context); + assertEquals(1, action.counter); + } + @Test - public void testDispatchWithBogusMethodSignature() throws Exception { - context.getAttributeMap().put(AnnotatedAction.METHOD_ATTRIBUTE, "bogus"); - try { - action.execute(context); - fail("Should've failed with no such method"); - } catch (MethodLookupException e) { - - } - } - + public void testDispatchWithBogusMethodSignature() throws Exception { + context.getAttributeMap().put(AnnotatedAction.METHOD_ATTRIBUTE, "bogus"); + try { + action.execute(context); + fail("Should've failed with no such method"); + } catch (MethodLookupException e) { + + } + } + @Test - public void testDispatchWithCurrentStateId() throws Exception { - MockFlowSession session = context.getMockFlowExecutionContext().getMockActiveSession(); - session.setState(new ViewState(session.getDefinitionInternal(), "increment", new StubViewFactory())); - action.execute(context); - assertEquals(1, action.counter); - } - + public void testDispatchWithCurrentStateId() throws Exception { + MockFlowSession session = context.getMockFlowExecutionContext().getMockActiveSession(); + session.setState(new ViewState(session.getDefinitionInternal(), "increment", new StubViewFactory())); + action.execute(context); + assertEquals(1, action.counter); + } + @Test - public void testNoSuchMethodWithCurrentStateId() throws Exception { - try { - action.execute(context); - fail("Should've failed with no such method"); - } catch (MethodLookupException e) { - - } - } - + public void testNoSuchMethodWithCurrentStateId() throws Exception { + try { + action.execute(context); + fail("Should've failed with no such method"); + } catch (MethodLookupException e) { + + } + } + @Test - public void testCannotResolveMethod() throws Exception { - try { - context.getMockFlowExecutionContext().getMockActiveSession().setState(null); - action.execute(context); - fail("Should've failed with illegal state"); - } catch (IllegalStateException e) { - - } - } - + public void testCannotResolveMethod() throws Exception { + try { + context.getMockFlowExecutionContext().getMockActiveSession().setState(null); + action.execute(context); + fail("Should've failed with illegal state"); + } catch (IllegalStateException e) { + + } + } + @Test - public void testCustomMethodResolver() throws Exception { - MethodResolver methodResolver = context -> "increment"; - action.setMethodResolver(methodResolver); - action.execute(context); - assertEquals(1, action.counter); - } + public void testCustomMethodResolver() throws Exception { + MethodResolver methodResolver = context -> "increment"; + action.setMethodResolver(methodResolver); + action.execute(context); + assertEquals(1, action.counter); + } } \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/action/ResultObjectBasedEventFactoryTests.java b/spring-webflow/src/test/java/org/springframework/webflow/action/ResultObjectBasedEventFactoryTests.java index 975443ea..9d058812 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/action/ResultObjectBasedEventFactoryTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/action/ResultObjectBasedEventFactoryTests.java @@ -1,93 +1,93 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.action; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.Date; - -import org.junit.jupiter.api.Test; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.test.MockRequestContext; - -/** - * Test case for {@link ResultObjectBasedEventFactory}. - * - * @author Erwin Vervaet - */ -public class ResultObjectBasedEventFactoryTests { - - private ResultObjectBasedEventFactory factory = new ResultObjectBasedEventFactory(); - +/* + * Copyright 2004-2012 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 + * + * https://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.action; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Date; + +import org.junit.jupiter.api.Test; +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.test.MockRequestContext; + +/** + * Test case for {@link ResultObjectBasedEventFactory}. + * + * @author Erwin Vervaet + */ +public class ResultObjectBasedEventFactoryTests { + + private ResultObjectBasedEventFactory factory = new ResultObjectBasedEventFactory(); + @Test - public void testNull() { - Event event = factory.createResultEvent(this, null, new MockRequestContext()); - assertEquals(factory.getNullEventId(), event.getId()); - } - + public void testNull() { + Event event = factory.createResultEvent(this, null, new MockRequestContext()); + assertEquals(factory.getNullEventId(), event.getId()); + } + @Test - public void testBoolean() { - Event event = factory.createResultEvent(this, true, new MockRequestContext()); - assertEquals(factory.getYesEventId(), event.getId()); - event = factory.createResultEvent(this, false, new MockRequestContext()); - assertEquals(factory.getNoEventId(), event.getId()); - } - + public void testBoolean() { + Event event = factory.createResultEvent(this, true, new MockRequestContext()); + assertEquals(factory.getYesEventId(), event.getId()); + event = factory.createResultEvent(this, false, new MockRequestContext()); + assertEquals(factory.getNoEventId(), event.getId()); + } + @Test - public void testLabeledEnum() { - Event event = factory.createResultEvent(this, MyLabeledEnum.A, new MockRequestContext()); - assertEquals("A", event.getId()); - assertSame(MyLabeledEnum.A, event.getAttributes().get("result")); - } - - public enum MyLabeledEnum { - A, B; - } - - /* - * public void testJava5Enum() { Event event = factory.createResultEvent(this, MyEnum.A, new MockRequestContext()); - * assertEquals("A", event.getId()); assertSame(MyEnum.A, event.getAttributes().get("result")); } - * - * public static enum MyEnum { A, B; - * - * public String toString() { return "MyEnum " + name(); } } - */ - + public void testLabeledEnum() { + Event event = factory.createResultEvent(this, MyLabeledEnum.A, new MockRequestContext()); + assertEquals("A", event.getId()); + assertSame(MyLabeledEnum.A, event.getAttributes().get("result")); + } + + public enum MyLabeledEnum { + A, B; + } + + /* + * public void testJava5Enum() { Event event = factory.createResultEvent(this, MyEnum.A, new MockRequestContext()); + * assertEquals("A", event.getId()); assertSame(MyEnum.A, event.getAttributes().get("result")); } + * + * public static enum MyEnum { A, B; + * + * public String toString() { return "MyEnum " + name(); } } + */ + @Test - public void testString() { - Event event = factory.createResultEvent(this, "foobar", new MockRequestContext()); - assertEquals("foobar", event.getId()); - } - + public void testString() { + Event event = factory.createResultEvent(this, "foobar", new MockRequestContext()); + assertEquals("foobar", event.getId()); + } + @Test - public void testEvent() { - Event orig = new Event(this, "test"); - Event event = factory.createResultEvent(this, orig, new MockRequestContext()); - assertSame(orig, event); - } - + public void testEvent() { + Event orig = new Event(this, "test"); + Event event = factory.createResultEvent(this, orig, new MockRequestContext()); + assertSame(orig, event); + } + @Test - public void testUnsupported() { - try { - factory.createResultEvent(this, new Date(), new MockRequestContext()); - fail(); - } catch (IllegalArgumentException e) { - // expected - } - } -} + public void testUnsupported() { + try { + factory.createResultEvent(this, new Date(), new MockRequestContext()); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/context/web/HttpSessionMapBindingListenerTests.java b/spring-webflow/src/test/java/org/springframework/webflow/context/web/HttpSessionMapBindingListenerTests.java index 49b66793..454872c3 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/context/web/HttpSessionMapBindingListenerTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/context/web/HttpSessionMapBindingListenerTests.java @@ -1,82 +1,82 @@ -/* - * 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 - * - * https://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.context.web; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.webflow.context.servlet.HttpSessionMap; -import org.springframework.webflow.core.collection.AttributeMapBindingEvent; -import org.springframework.webflow.core.collection.AttributeMapBindingListener; - -/** - * Unit tests for {@link HttpSessionMapBindingListener}. - * - * @author Erwin Vervaet - */ -public class HttpSessionMapBindingListenerTests { - - private HttpServletRequest request; - private HttpSession session; - private TestAttributeMapBindingListener value; - +/* + * 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 + * + * https://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.context.web; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.webflow.context.servlet.HttpSessionMap; +import org.springframework.webflow.core.collection.AttributeMapBindingEvent; +import org.springframework.webflow.core.collection.AttributeMapBindingListener; + +/** + * Unit tests for {@link HttpSessionMapBindingListener}. + * + * @author Erwin Vervaet + */ +public class HttpSessionMapBindingListenerTests { + + private HttpServletRequest request; + private HttpSession session; + private TestAttributeMapBindingListener value; + @BeforeEach - public void setUp() throws Exception { - request = new MockHttpServletRequest(); - session = request.getSession(true); - value = new TestAttributeMapBindingListener(); - } - + public void setUp() throws Exception { + request = new MockHttpServletRequest(); + session = request.getSession(true); + value = new TestAttributeMapBindingListener(); + } + @Test - public void testValueBoundUnBound() { - value.valueBoundEvent = null; - value.valueUnboundEvent = null; - session.setAttribute("key", new HttpSessionMapBindingListener(value, new HttpSessionMap(request))); - assertNotNull(value.valueBoundEvent); - assertNull(value.valueUnboundEvent); - value.valueBoundEvent = null; - value.valueUnboundEvent = null; - session.removeAttribute("key"); - assertNull(value.valueBoundEvent); - assertNotNull(value.valueUnboundEvent); - } - - private static class TestAttributeMapBindingListener implements AttributeMapBindingListener { - - public AttributeMapBindingEvent valueBoundEvent; - public AttributeMapBindingEvent valueUnboundEvent; - - public void valueBound(AttributeMapBindingEvent event) { - this.valueBoundEvent = event; - assertEquals("key", event.getAttributeName()); - assertSame(event.getAttributeValue(), this); - } - - public void valueUnbound(AttributeMapBindingEvent event) { - this.valueUnboundEvent = event; - assertEquals("key", event.getAttributeName()); - assertSame(event.getAttributeValue(), this); - } - } -} + public void testValueBoundUnBound() { + value.valueBoundEvent = null; + value.valueUnboundEvent = null; + session.setAttribute("key", new HttpSessionMapBindingListener(value, new HttpSessionMap(request))); + assertNotNull(value.valueBoundEvent); + assertNull(value.valueUnboundEvent); + value.valueBoundEvent = null; + value.valueUnboundEvent = null; + session.removeAttribute("key"); + assertNull(value.valueBoundEvent); + assertNotNull(value.valueUnboundEvent); + } + + private static class TestAttributeMapBindingListener implements AttributeMapBindingListener { + + public AttributeMapBindingEvent valueBoundEvent; + public AttributeMapBindingEvent valueUnboundEvent; + + public void valueBound(AttributeMapBindingEvent event) { + this.valueBoundEvent = event; + assertEquals("key", event.getAttributeName()); + assertSame(event.getAttributeValue(), this); + } + + public void valueUnbound(AttributeMapBindingEvent event) { + this.valueUnboundEvent = event; + assertEquals("key", event.getAttributeName()); + assertSame(event.getAttributeValue(), this); + } + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/conversation/impl/SessionBindingConversationManagerTests.java b/spring-webflow/src/test/java/org/springframework/webflow/conversation/impl/SessionBindingConversationManagerTests.java index 288166ff..5ea22458 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/conversation/impl/SessionBindingConversationManagerTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/conversation/impl/SessionBindingConversationManagerTests.java @@ -1,168 +1,168 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.conversation.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.fail; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.webflow.context.ExternalContextHolder; -import org.springframework.webflow.conversation.Conversation; -import org.springframework.webflow.conversation.ConversationException; -import org.springframework.webflow.conversation.ConversationId; -import org.springframework.webflow.conversation.ConversationParameters; -import org.springframework.webflow.core.collection.SharedAttributeMap; -import org.springframework.webflow.test.MockExternalContext; - -/** - * Unit tests for {@link SessionBindingConversationManager}. - */ -public class SessionBindingConversationManagerTests { - - private SessionBindingConversationManager conversationManager; - +/* + * Copyright 2004-2012 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 + * + * https://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.conversation.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.webflow.context.ExternalContextHolder; +import org.springframework.webflow.conversation.Conversation; +import org.springframework.webflow.conversation.ConversationException; +import org.springframework.webflow.conversation.ConversationId; +import org.springframework.webflow.conversation.ConversationParameters; +import org.springframework.webflow.core.collection.SharedAttributeMap; +import org.springframework.webflow.test.MockExternalContext; + +/** + * Unit tests for {@link SessionBindingConversationManager}. + */ +public class SessionBindingConversationManagerTests { + + private SessionBindingConversationManager conversationManager; + @BeforeEach - public void setUp() throws Exception { - conversationManager = new SessionBindingConversationManager(); - } - - @AfterEach - public void tearDown() throws Exception { - ExternalContextHolder.setExternalContext(null); - } - + public void setUp() throws Exception { + conversationManager = new SessionBindingConversationManager(); + } + + @AfterEach + public void tearDown() throws Exception { + ExternalContextHolder.setExternalContext(null); + } + @Test - public void testConversationLifeCycle() { - ExternalContextHolder.setExternalContext(new MockExternalContext()); - Conversation conversation = conversationManager.beginConversation(new ConversationParameters("test", "test", - "test")); - ConversationId conversationId = conversation.getId(); - assertNotNull(conversationManager.getConversation(conversationId)); - conversation.lock(); - conversation.end(); - conversation.unlock(); - try { - conversationManager.getConversation(conversationId); - fail("Conversation should have ben removed"); - } catch (ConversationException e) { - } - } - + public void testConversationLifeCycle() { + ExternalContextHolder.setExternalContext(new MockExternalContext()); + Conversation conversation = conversationManager.beginConversation(new ConversationParameters("test", "test", + "test")); + ConversationId conversationId = conversation.getId(); + assertNotNull(conversationManager.getConversation(conversationId)); + conversation.lock(); + conversation.end(); + conversation.unlock(); + try { + conversationManager.getConversation(conversationId); + fail("Conversation should have ben removed"); + } catch (ConversationException e) { + } + } + @Test - public void testNoPassivation() { - ExternalContextHolder.setExternalContext(new MockExternalContext()); - Conversation conversation = conversationManager.beginConversation(new ConversationParameters("test", "test", - "test")); - conversation.lock(); - conversation.putAttribute("testAttribute", "testValue"); - ConversationId conversationId = conversation.getId(); - - Conversation conversation2 = conversationManager.getConversation(conversationId); - assertSame(conversation, conversation2); - conversation2.lock(); - assertEquals("testValue", conversation2.getAttribute("testAttribute")); - conversation.end(); - conversation.unlock(); - conversation2.unlock(); - } - + public void testNoPassivation() { + ExternalContextHolder.setExternalContext(new MockExternalContext()); + Conversation conversation = conversationManager.beginConversation(new ConversationParameters("test", "test", + "test")); + conversation.lock(); + conversation.putAttribute("testAttribute", "testValue"); + ConversationId conversationId = conversation.getId(); + + Conversation conversation2 = conversationManager.getConversation(conversationId); + assertSame(conversation, conversation2); + conversation2.lock(); + assertEquals("testValue", conversation2.getAttribute("testAttribute")); + conversation.end(); + conversation.unlock(); + conversation2.unlock(); + } + @Test - public void testPassivation() throws Exception { - MockExternalContext externalContext = new MockExternalContext(); - ExternalContextHolder.setExternalContext(externalContext); - Conversation conversation = conversationManager.beginConversation(new ConversationParameters("test", "test", - "test")); - conversation.lock(); - conversation.putAttribute("testAttribute", "testValue"); - ConversationId conversationId = conversation.getId(); - ExternalContextHolder.setExternalContext(null); - // simulate write out of session - byte[] passiveSession = passivate(externalContext.getSessionMap()); - - // simulate start-up of server - conversationManager = new SessionBindingConversationManager(); - String id = conversationId.toString(); - conversationId = conversationManager.parseConversationId(id); - - // simulate restore of session - externalContext.setSessionMap(activate(passiveSession)); - ExternalContextHolder.setExternalContext(externalContext); - Conversation conversation2 = conversationManager.getConversation(conversationId); - assertNotSame(conversation, conversation2); - assertEquals("testValue", conversation2.getAttribute("testAttribute")); - conversation.end(); - conversation.unlock(); - } - + public void testPassivation() throws Exception { + MockExternalContext externalContext = new MockExternalContext(); + ExternalContextHolder.setExternalContext(externalContext); + Conversation conversation = conversationManager.beginConversation(new ConversationParameters("test", "test", + "test")); + conversation.lock(); + conversation.putAttribute("testAttribute", "testValue"); + ConversationId conversationId = conversation.getId(); + ExternalContextHolder.setExternalContext(null); + // simulate write out of session + byte[] passiveSession = passivate(externalContext.getSessionMap()); + + // simulate start-up of server + conversationManager = new SessionBindingConversationManager(); + String id = conversationId.toString(); + conversationId = conversationManager.parseConversationId(id); + + // simulate restore of session + externalContext.setSessionMap(activate(passiveSession)); + ExternalContextHolder.setExternalContext(externalContext); + Conversation conversation2 = conversationManager.getConversation(conversationId); + assertNotSame(conversation, conversation2); + assertEquals("testValue", conversation2.getAttribute("testAttribute")); + conversation.end(); + conversation.unlock(); + } + @Test - public void testMaxConversations() { - conversationManager.setMaxConversations(2); - ExternalContextHolder.setExternalContext(new MockExternalContext()); - Conversation conversation1 = conversationManager.beginConversation(new ConversationParameters("test", "test", - "test")); - conversation1.lock(); - assertNotNull(conversationManager.getConversation(conversation1.getId())); - Conversation conversation2 = conversationManager.beginConversation(new ConversationParameters("test", "test", - "test")); - assertNotNull(conversationManager.getConversation(conversation1.getId())); - assertNotNull(conversationManager.getConversation(conversation2.getId())); - Conversation conversation3 = conversationManager.beginConversation(new ConversationParameters("test", "test", - "test")); - try { - conversation1.end(); - conversation1.unlock(); - conversationManager.getConversation(conversation1.getId()); - fail(); - } catch (ConversationException e) { - } - assertNotNull(conversationManager.getConversation(conversation2.getId())); - assertNotNull(conversationManager.getConversation(conversation3.getId())); - } - + public void testMaxConversations() { + conversationManager.setMaxConversations(2); + ExternalContextHolder.setExternalContext(new MockExternalContext()); + Conversation conversation1 = conversationManager.beginConversation(new ConversationParameters("test", "test", + "test")); + conversation1.lock(); + assertNotNull(conversationManager.getConversation(conversation1.getId())); + Conversation conversation2 = conversationManager.beginConversation(new ConversationParameters("test", "test", + "test")); + assertNotNull(conversationManager.getConversation(conversation1.getId())); + assertNotNull(conversationManager.getConversation(conversation2.getId())); + Conversation conversation3 = conversationManager.beginConversation(new ConversationParameters("test", "test", + "test")); + try { + conversation1.end(); + conversation1.unlock(); + conversationManager.getConversation(conversation1.getId()); + fail(); + } catch (ConversationException e) { + } + assertNotNull(conversationManager.getConversation(conversation2.getId())); + assertNotNull(conversationManager.getConversation(conversation3.getId())); + } + @Test - public void testCustomSessionKey() { - conversationManager.setSessionKey("foo"); - MockExternalContext context = new MockExternalContext(); - ExternalContextHolder.setExternalContext(context); - conversationManager.beginConversation(new ConversationParameters("test", "test", "test")); - assertNotNull(context.getSessionMap().get("foo")); - } - - private byte[] passivate(SharedAttributeMap session) throws Exception { - // session is serialized out - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - ObjectOutputStream oout = new ObjectOutputStream(bout); - oout.writeObject(session); - return bout.toByteArray(); - } - - @SuppressWarnings("unchecked") - private SharedAttributeMap activate(byte[] sessionData) throws Exception { - // session is serialized back in - return (SharedAttributeMap) new ObjectInputStream(new ByteArrayInputStream(sessionData)).readObject(); - } - + public void testCustomSessionKey() { + conversationManager.setSessionKey("foo"); + MockExternalContext context = new MockExternalContext(); + ExternalContextHolder.setExternalContext(context); + conversationManager.beginConversation(new ConversationParameters("test", "test", "test")); + assertNotNull(context.getSessionMap().get("foo")); + } + + private byte[] passivate(SharedAttributeMap session) throws Exception { + // session is serialized out + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ObjectOutputStream oout = new ObjectOutputStream(bout); + oout.writeObject(session); + return bout.toByteArray(); + } + + @SuppressWarnings("unchecked") + private SharedAttributeMap activate(byte[] sessionData) throws Exception { + // session is serialized back in + return (SharedAttributeMap) new ObjectInputStream(new ByteArrayInputStream(sessionData)).readObject(); + } + } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/core/collection/CollectionUtilsTests.java b/spring-webflow/src/test/java/org/springframework/webflow/core/collection/CollectionUtilsTests.java index 7ff0a4ca..7134cf96 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/core/collection/CollectionUtilsTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/core/collection/CollectionUtilsTests.java @@ -1,33 +1,33 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@link CollectionUtils}. - */ -public class CollectionUtilsTests { - +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link CollectionUtils}. + */ +public class CollectionUtilsTests { + @Test - public void testSingleEntryMap() { - AttributeMap map1 = CollectionUtils.singleEntryMap("foo", "bar"); - AttributeMap map2 = CollectionUtils.singleEntryMap("foo", "bar"); - assertEquals(map1, map2); - } -} + public void testSingleEntryMap() { + AttributeMap map1 = CollectionUtils.singleEntryMap("foo", "bar"); + AttributeMap map2 = CollectionUtils.singleEntryMap("foo", "bar"); + assertEquals(map1, map2); + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/core/collection/LocalAttributeMapTests.java b/spring-webflow/src/test/java/org/springframework/webflow/core/collection/LocalAttributeMapTests.java index 68cf0988..e9432e0b 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/core/collection/LocalAttributeMapTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/core/collection/LocalAttributeMapTests.java @@ -1,391 +1,391 @@ -/* - * Copyright 2004-2020 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 - * - * https://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.core.collection; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.math.BigDecimal; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -/** - * Unit tests for {@link LocalAttributeMap}. - */ -public class LocalAttributeMapTests { - - private LocalAttributeMap attributeMap = new LocalAttributeMap<>(); - - @BeforeEach - public void setUp() { - attributeMap.put("string", "A string"); - attributeMap.put("integer", 12345); - attributeMap.put("boolean", true); - attributeMap.put("long", 12345L); - attributeMap.put("double", 12345d); - attributeMap.put("float", 12345f); - attributeMap.put("bigDecimal", new BigDecimal("12345.67")); - attributeMap.put("bean", new TestBean()); - attributeMap.put("stringArray", new String[] { "1", "2", "3" }); - attributeMap.put("collection", new LinkedList<>()); - } - - @Test - public void testGet() { - TestBean bean = (TestBean) attributeMap.get("bean"); - assertNotNull(bean); - } - - @Test - public void testGetNull() { - TestBean bean = (TestBean) attributeMap.get("bogus"); - assertNull(bean); - } - - @Test - public void testGetRequiredType() { - TestBean bean = attributeMap.get("bean", TestBean.class); - assertNotNull(bean); - } - - @Test - public void testGetWrongType() { - try { - attributeMap.get("bean", String.class); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @Test - public void testGetWithDefaultOption() { - TestBean d = new TestBean(); - TestBean bean = (TestBean) attributeMap.get("bean", d); - assertNotNull(bean); - assertNotSame(bean, d); - } - - @Test - public void testGetWithDefault() { - TestBean d = new TestBean(); - TestBean bean = (TestBean) attributeMap.get("bogus", d); - assertSame(bean, d); - } - - @Test - public void testGetRequired() { - TestBean bean = (TestBean) attributeMap.getRequired("bean"); - assertNotNull(bean); - } - - @Test - public void testGetRequiredNotPresent() { - try { - attributeMap.getRequired("bogus"); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @Test - public void testGetRequiredOfType() { - TestBean bean = attributeMap.getRequired("bean", TestBean.class); - assertNotNull(bean); - } - - @Test - public void testGetRequiredWrongType() { - try { - attributeMap.getRequired("bean", String.class); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @Test - public void testGetNumber() { - BigDecimal bd = attributeMap.getNumber("bigDecimal", BigDecimal.class); - assertEquals(new BigDecimal("12345.67"), bd); - } - - @Test - public void testGetNumberWrongType() { - try { - attributeMap.getNumber("bigDecimal", Integer.class); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @Test - public void testGetNumberWithDefaultOption() { - BigDecimal d = new BigDecimal("1"); - BigDecimal bd = attributeMap.getNumber("bigDecimal", BigDecimal.class, d); - assertEquals(new BigDecimal("12345.67"), bd); - assertNotSame(d, bd); - } - - @Test - public void testGetNumberWithDefault() { - BigDecimal d = new BigDecimal("1"); - BigDecimal bd = attributeMap.getNumber("bogus", BigDecimal.class, d); - assertEquals(d, bd); - assertSame(d, bd); - } - - @Test - public void testGetNumberRequired() { - BigDecimal bd = attributeMap.getRequiredNumber("bigDecimal", BigDecimal.class); - assertEquals(new BigDecimal("12345.67"), bd); - } - - @Test - public void testGetNumberRequiredNotPresent() { - try { - attributeMap.getRequiredNumber("bogus", BigDecimal.class); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @Test - public void testGetInteger() { - Integer i = attributeMap.getInteger("integer"); - assertEquals(new Integer(12345), i); - } - - @Test - public void testGetIntegerNull() { - Integer i = attributeMap.getInteger("bogus"); - assertNull(i); - } - - @Test - public void testGetIntegerRequired() { - Integer i = attributeMap.getRequiredInteger("integer"); - assertEquals(new Integer(12345), i); - } - - @Test - public void testGetIntegerRequiredNotPresent() { - try { - attributeMap.getRequiredInteger("bogus"); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @Test - public void testGetLong() { - Long i = attributeMap.getLong("long"); - assertEquals(new Long(12345), i); - } - - @Test - public void testGetLongNull() { - Long i = attributeMap.getLong("bogus"); - assertNull(i); - } - - @Test - public void testGetLongRequired() { - Long i = attributeMap.getRequiredLong("long"); - assertEquals(new Long(12345), i); - } - - @Test - public void testGetLongRequiredNotPresent() { - try { - attributeMap.getRequiredLong("bogus"); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @Test - public void testGetString() { - String i = attributeMap.getString("string"); - assertEquals("A string", i); - } - - @Test - public void testGetStringNull() { - String i = attributeMap.getString("bogus"); - assertNull(i); - } - - @Test - public void testGetStringRequired() { - String i = attributeMap.getRequiredString("string"); - assertEquals("A string", i); - } - - @Test - public void testGetStringRequiredNotPresent() { - try { - attributeMap.getRequiredString("bogus"); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @Test - public void testGetBoolean() { - Boolean i = attributeMap.getBoolean("boolean"); - assertEquals(Boolean.TRUE, i); - } - - @Test - public void testGetBooleanNull() { - Boolean i = attributeMap.getBoolean("bogus"); - assertNull(i); - } - - @Test - public void testGetBooleanRequired() { - Boolean i = attributeMap.getRequiredBoolean("boolean"); - assertEquals(Boolean.TRUE, i); - } - - @Test - public void testGetBooleanRequiredNotPresent() { - try { - attributeMap.getRequiredBoolean("bogus"); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @Test - public void testGetArray() { - String[] i = attributeMap.getArray("stringArray", String[].class); - assertEquals(3, i.length); - } - - @Test - public void testGetArrayNull() { - String[] i = attributeMap.getArray("A bogus array", String[].class); - assertNull(i); - } - - @Test - public void testGetArrayRequired() { - String[] i = attributeMap.getRequiredArray("stringArray", String[].class); - assertEquals(3, i.length); - } - - @Test - public void testGetArrayRequiredNotPresent() { - try { - attributeMap.getRequiredArray("A bogus array", String[].class); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @SuppressWarnings("unchecked") - @Test - public void testGetCollection() { - List i = attributeMap.getCollection("collection", List.class); - assertTrue(i instanceof LinkedList); - assertEquals(0, i.size()); - } - - @SuppressWarnings("unchecked") - @Test - public void testGetCollectionNull() { - List i = attributeMap.getCollection("bogus", List.class); - assertNull(i); - } - - @SuppressWarnings("unchecked") - @Test - public void testGetCollectionRequired() { - List i = attributeMap.getRequiredCollection("collection", List.class); - assertEquals(0, i.size()); - } - - @Test - public void testGetCollectionRequiredNotPresent() { - try { - attributeMap.getRequiredCollection("A bogus collection"); - fail("Should've failed iae"); - } catch (IllegalArgumentException e) { - - } - } - - @Test - public void testGetMap() { - Map map = attributeMap.asMap(); - assertEquals(10, map.size()); - } - - @Test - public void testUnion() { - LocalAttributeMap one = new LocalAttributeMap<>(); - one.put("foo", "bar"); - one.put("bar", "baz"); - - LocalAttributeMap two = new LocalAttributeMap<>(); - two.put("cat", "coz"); - two.put("bar", "boo"); - - AttributeMap three = one.union(two); - assertEquals(3, three.size()); - assertEquals("bar", three.get("foo")); - assertEquals("coz", three.get("cat")); - assertEquals("boo", three.get("bar")); - } - - @Test - public void testEquality() { - LocalAttributeMap map = new LocalAttributeMap<>(); - map.put("foo", "bar"); - - LocalAttributeMap map2 = new LocalAttributeMap<>(); - map2.put("foo", "bar"); - - assertEquals(map, map2); - } - - @Test - public void testExtract() { - assertEquals("A string", attributeMap.extract("string")); - assertFalse(attributeMap.contains("string")); - } - -} +/* + * Copyright 2004-2020 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 + * + * https://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.core.collection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.math.BigDecimal; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link LocalAttributeMap}. + */ +public class LocalAttributeMapTests { + + private LocalAttributeMap attributeMap = new LocalAttributeMap<>(); + + @BeforeEach + public void setUp() { + attributeMap.put("string", "A string"); + attributeMap.put("integer", 12345); + attributeMap.put("boolean", true); + attributeMap.put("long", 12345L); + attributeMap.put("double", 12345d); + attributeMap.put("float", 12345f); + attributeMap.put("bigDecimal", new BigDecimal("12345.67")); + attributeMap.put("bean", new TestBean()); + attributeMap.put("stringArray", new String[] { "1", "2", "3" }); + attributeMap.put("collection", new LinkedList<>()); + } + + @Test + public void testGet() { + TestBean bean = (TestBean) attributeMap.get("bean"); + assertNotNull(bean); + } + + @Test + public void testGetNull() { + TestBean bean = (TestBean) attributeMap.get("bogus"); + assertNull(bean); + } + + @Test + public void testGetRequiredType() { + TestBean bean = attributeMap.get("bean", TestBean.class); + assertNotNull(bean); + } + + @Test + public void testGetWrongType() { + try { + attributeMap.get("bean", String.class); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void testGetWithDefaultOption() { + TestBean d = new TestBean(); + TestBean bean = (TestBean) attributeMap.get("bean", d); + assertNotNull(bean); + assertNotSame(bean, d); + } + + @Test + public void testGetWithDefault() { + TestBean d = new TestBean(); + TestBean bean = (TestBean) attributeMap.get("bogus", d); + assertSame(bean, d); + } + + @Test + public void testGetRequired() { + TestBean bean = (TestBean) attributeMap.getRequired("bean"); + assertNotNull(bean); + } + + @Test + public void testGetRequiredNotPresent() { + try { + attributeMap.getRequired("bogus"); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void testGetRequiredOfType() { + TestBean bean = attributeMap.getRequired("bean", TestBean.class); + assertNotNull(bean); + } + + @Test + public void testGetRequiredWrongType() { + try { + attributeMap.getRequired("bean", String.class); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void testGetNumber() { + BigDecimal bd = attributeMap.getNumber("bigDecimal", BigDecimal.class); + assertEquals(new BigDecimal("12345.67"), bd); + } + + @Test + public void testGetNumberWrongType() { + try { + attributeMap.getNumber("bigDecimal", Integer.class); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void testGetNumberWithDefaultOption() { + BigDecimal d = new BigDecimal("1"); + BigDecimal bd = attributeMap.getNumber("bigDecimal", BigDecimal.class, d); + assertEquals(new BigDecimal("12345.67"), bd); + assertNotSame(d, bd); + } + + @Test + public void testGetNumberWithDefault() { + BigDecimal d = new BigDecimal("1"); + BigDecimal bd = attributeMap.getNumber("bogus", BigDecimal.class, d); + assertEquals(d, bd); + assertSame(d, bd); + } + + @Test + public void testGetNumberRequired() { + BigDecimal bd = attributeMap.getRequiredNumber("bigDecimal", BigDecimal.class); + assertEquals(new BigDecimal("12345.67"), bd); + } + + @Test + public void testGetNumberRequiredNotPresent() { + try { + attributeMap.getRequiredNumber("bogus", BigDecimal.class); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void testGetInteger() { + Integer i = attributeMap.getInteger("integer"); + assertEquals(new Integer(12345), i); + } + + @Test + public void testGetIntegerNull() { + Integer i = attributeMap.getInteger("bogus"); + assertNull(i); + } + + @Test + public void testGetIntegerRequired() { + Integer i = attributeMap.getRequiredInteger("integer"); + assertEquals(new Integer(12345), i); + } + + @Test + public void testGetIntegerRequiredNotPresent() { + try { + attributeMap.getRequiredInteger("bogus"); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void testGetLong() { + Long i = attributeMap.getLong("long"); + assertEquals(new Long(12345), i); + } + + @Test + public void testGetLongNull() { + Long i = attributeMap.getLong("bogus"); + assertNull(i); + } + + @Test + public void testGetLongRequired() { + Long i = attributeMap.getRequiredLong("long"); + assertEquals(new Long(12345), i); + } + + @Test + public void testGetLongRequiredNotPresent() { + try { + attributeMap.getRequiredLong("bogus"); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void testGetString() { + String i = attributeMap.getString("string"); + assertEquals("A string", i); + } + + @Test + public void testGetStringNull() { + String i = attributeMap.getString("bogus"); + assertNull(i); + } + + @Test + public void testGetStringRequired() { + String i = attributeMap.getRequiredString("string"); + assertEquals("A string", i); + } + + @Test + public void testGetStringRequiredNotPresent() { + try { + attributeMap.getRequiredString("bogus"); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void testGetBoolean() { + Boolean i = attributeMap.getBoolean("boolean"); + assertEquals(Boolean.TRUE, i); + } + + @Test + public void testGetBooleanNull() { + Boolean i = attributeMap.getBoolean("bogus"); + assertNull(i); + } + + @Test + public void testGetBooleanRequired() { + Boolean i = attributeMap.getRequiredBoolean("boolean"); + assertEquals(Boolean.TRUE, i); + } + + @Test + public void testGetBooleanRequiredNotPresent() { + try { + attributeMap.getRequiredBoolean("bogus"); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void testGetArray() { + String[] i = attributeMap.getArray("stringArray", String[].class); + assertEquals(3, i.length); + } + + @Test + public void testGetArrayNull() { + String[] i = attributeMap.getArray("A bogus array", String[].class); + assertNull(i); + } + + @Test + public void testGetArrayRequired() { + String[] i = attributeMap.getRequiredArray("stringArray", String[].class); + assertEquals(3, i.length); + } + + @Test + public void testGetArrayRequiredNotPresent() { + try { + attributeMap.getRequiredArray("A bogus array", String[].class); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @SuppressWarnings("unchecked") + @Test + public void testGetCollection() { + List i = attributeMap.getCollection("collection", List.class); + assertTrue(i instanceof LinkedList); + assertEquals(0, i.size()); + } + + @SuppressWarnings("unchecked") + @Test + public void testGetCollectionNull() { + List i = attributeMap.getCollection("bogus", List.class); + assertNull(i); + } + + @SuppressWarnings("unchecked") + @Test + public void testGetCollectionRequired() { + List i = attributeMap.getRequiredCollection("collection", List.class); + assertEquals(0, i.size()); + } + + @Test + public void testGetCollectionRequiredNotPresent() { + try { + attributeMap.getRequiredCollection("A bogus collection"); + fail("Should've failed iae"); + } catch (IllegalArgumentException e) { + + } + } + + @Test + public void testGetMap() { + Map map = attributeMap.asMap(); + assertEquals(10, map.size()); + } + + @Test + public void testUnion() { + LocalAttributeMap one = new LocalAttributeMap<>(); + one.put("foo", "bar"); + one.put("bar", "baz"); + + LocalAttributeMap two = new LocalAttributeMap<>(); + two.put("cat", "coz"); + two.put("bar", "boo"); + + AttributeMap three = one.union(two); + assertEquals(3, three.size()); + assertEquals("bar", three.get("foo")); + assertEquals("coz", three.get("cat")); + assertEquals("boo", three.get("bar")); + } + + @Test + public void testEquality() { + LocalAttributeMap map = new LocalAttributeMap<>(); + map.put("foo", "bar"); + + LocalAttributeMap map2 = new LocalAttributeMap<>(); + map2.put("foo", "bar"); + + assertEquals(map, map2); + } + + @Test + public void testExtract() { + assertEquals("A string", attributeMap.extract("string")); + assertFalse(attributeMap.contains("string")); + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/core/collection/LocalParameterMapTests.java b/spring-webflow/src/test/java/org/springframework/webflow/core/collection/LocalParameterMapTests.java index 76fd194a..aece6f99 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/core/collection/LocalParameterMapTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/core/collection/LocalParameterMapTests.java @@ -1,295 +1,295 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.core.collection; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.util.HashMap; -import java.util.Map; - -import org.easymock.EasyMock; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.web.multipart.MultipartFile; - -/** - * Unit tests for {@link LocalParameterMap}. - */ -public class LocalParameterMapTests { - - private LocalParameterMap parameterMap; - - @BeforeEach - public void setUp() { - Map map = new HashMap<>(); - map.put("string", "A string"); - map.put("integer", "12345"); - map.put("boolean", "true"); - map.put("stringArray", new String[] { "1", "2", "3" }); - map.put("emptyArray", new String[0]); - map.put("multipartFile", EasyMock.createMock(MultipartFile.class)); - parameterMap = new LocalParameterMap(map); - } - +/* + * Copyright 2004-2012 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 + * + * https://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.core.collection; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.HashMap; +import java.util.Map; + +import org.easymock.EasyMock; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.web.multipart.MultipartFile; + +/** + * Unit tests for {@link LocalParameterMap}. + */ +public class LocalParameterMapTests { + + private LocalParameterMap parameterMap; + + @BeforeEach + public void setUp() { + Map map = new HashMap<>(); + map.put("string", "A string"); + map.put("integer", "12345"); + map.put("boolean", "true"); + map.put("stringArray", new String[] { "1", "2", "3" }); + map.put("emptyArray", new String[0]); + map.put("multipartFile", EasyMock.createMock(MultipartFile.class)); + parameterMap = new LocalParameterMap(map); + } + @Test - public void testSize() { - assertTrue(!parameterMap.isEmpty()); - assertEquals(6, parameterMap.size()); - } - + public void testSize() { + assertTrue(!parameterMap.isEmpty()); + assertEquals(6, parameterMap.size()); + } + @Test - public void testGet() { - String value = parameterMap.get("string"); - assertEquals("A string", value); - } - + public void testGet() { + String value = parameterMap.get("string"); + assertEquals("A string", value); + } + @Test - public void testGetNull() { - String value = parameterMap.get("bogus"); - assertNull(value); - } - + public void testGetNull() { + String value = parameterMap.get("bogus"); + assertNull(value); + } + @Test - public void testGetRequired() { - String value = parameterMap.getRequired("string"); - assertEquals("A string", value); - } - + public void testGetRequired() { + String value = parameterMap.getRequired("string"); + assertEquals("A string", value); + } + @Test - public void testGetRequiredWithConversion() { - Integer value = parameterMap.getRequired("integer", Integer.class); - assertEquals(new Integer(12345), value); - } - + public void testGetRequiredWithConversion() { + Integer value = parameterMap.getRequired("integer", Integer.class); + assertEquals(new Integer(12345), value); + } + @Test - public void testGetRequiredNotPresent() { - try { - parameterMap.getRequired("bogus"); - } catch (IllegalArgumentException e) { - - } - } - + public void testGetRequiredNotPresent() { + try { + parameterMap.getRequired("bogus"); + } catch (IllegalArgumentException e) { + + } + } + @Test - public void testGetWithDefaultOption() { - String value = parameterMap.get("string", "default"); - assertEquals("A string", value); - } - + public void testGetWithDefaultOption() { + String value = parameterMap.get("string", "default"); + assertEquals("A string", value); + } + @Test - public void testGetWithDefault() { - String value = parameterMap.get("bogus", "default"); - assertEquals("default", value); - } - + public void testGetWithDefault() { + String value = parameterMap.get("bogus", "default"); + assertEquals("default", value); + } + @Test - public void testGetWithDefaultAndConversion() { - Object value = parameterMap.get("bogus", Integer.class, 1); - assertEquals(1, value); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) + public void testGetWithDefaultAndConversion() { + Object value = parameterMap.get("bogus", Integer.class, 1); + assertEquals(1, value); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) @Test - public void testGetWithDefaultAndConversionNotAssignable() { - try { - parameterMap.get("bogus", (Class) Integer.class, "1"); - fail("'1' isn't a integer"); - } catch (IllegalArgumentException e) { - - } - } - + public void testGetWithDefaultAndConversionNotAssignable() { + try { + parameterMap.get("bogus", (Class) Integer.class, "1"); + fail("'1' isn't a integer"); + } catch (IllegalArgumentException e) { + + } + } + @Test - public void testGetArray() { - String[] value = parameterMap.getArray("stringArray"); - assertEquals(3, value.length); - } - + public void testGetArray() { + String[] value = parameterMap.getArray("stringArray"); + assertEquals(3, value.length); + } + @Test - public void testGetEmptyArray() { - String[] array = parameterMap.getArray("emptyArray"); - assertEquals(0, array.length); - } - + public void testGetEmptyArray() { + String[] array = parameterMap.getArray("emptyArray"); + assertEquals(0, array.length); + } + @Test - public void testGetArrayNull() { - String[] value = parameterMap.getArray("bogus"); - assertNull(value); - } - + public void testGetArrayNull() { + String[] value = parameterMap.getArray("bogus"); + assertNull(value); + } + @Test - public void testGetArrayRequired() { - String[] value = parameterMap.getRequiredArray("stringArray"); - assertEquals(3, value.length); - } - - public void getArrayWithConversion() { - Integer[] values = parameterMap.getArray("stringArray", Integer.class); - assertEquals(new Integer(1), values[0]); - assertEquals(new Integer(2), values[1]); - assertEquals(new Integer(3), values[2]); - } - + public void testGetArrayRequired() { + String[] value = parameterMap.getRequiredArray("stringArray"); + assertEquals(3, value.length); + } + + public void getArrayWithConversion() { + Integer[] values = parameterMap.getArray("stringArray", Integer.class); + assertEquals(new Integer(1), values[0]); + assertEquals(new Integer(2), values[1]); + assertEquals(new Integer(3), values[2]); + } + @Test - public void testGetRequiredArrayNotPresent() { - try { - parameterMap.getRequiredArray("bogus"); - } catch (IllegalArgumentException e) { - - } - } - + public void testGetRequiredArrayNotPresent() { + try { + parameterMap.getRequiredArray("bogus"); + } catch (IllegalArgumentException e) { + + } + } + @Test - public void testGetSingleValueAsArray() { - String[] value = parameterMap.getArray("string"); - assertEquals(1, value.length); - assertEquals("A string", value[0]); - } - + public void testGetSingleValueAsArray() { + String[] value = parameterMap.getArray("string"); + assertEquals(1, value.length); + assertEquals("A string", value[0]); + } + @Test - public void testGetArrayAsSingleVaue() { - String value = parameterMap.get("stringArray"); - assertEquals("1", value); - } - + public void testGetArrayAsSingleVaue() { + String value = parameterMap.get("stringArray"); + assertEquals("1", value); + } + @Test - public void testGetEmptyArrayAsSingleVaue() { - String value = parameterMap.get("emptyArray"); - assertEquals(null, value); - } - + public void testGetEmptyArrayAsSingleVaue() { + String value = parameterMap.get("emptyArray"); + assertEquals(null, value); + } + @Test - public void testGetConversion() { - Integer i = parameterMap.getInteger("integer"); - assertEquals(new Integer(12345), i); - } - + public void testGetConversion() { + Integer i = parameterMap.getInteger("integer"); + assertEquals(new Integer(12345), i); + } + @Test - public void testGetArrayConversion() { - Integer[] i = parameterMap.getArray("stringArray", Integer.class); - assertEquals(i.length, 3); - assertEquals(new Integer(1), i[0]); - assertEquals(new Integer(2), i[1]); - assertEquals(new Integer(3), i[2]); - } - - public void getRequiredArrayWithConversion() { - Integer[] values = parameterMap.getRequiredArray("stringArray", Integer.class); - assertEquals(new Integer(1), values[0]); - assertEquals(new Integer(2), values[1]); - assertEquals(new Integer(3), values[2]); - } - + public void testGetArrayConversion() { + Integer[] i = parameterMap.getArray("stringArray", Integer.class); + assertEquals(i.length, 3); + assertEquals(new Integer(1), i[0]); + assertEquals(new Integer(2), i[1]); + assertEquals(new Integer(3), i[2]); + } + + public void getRequiredArrayWithConversion() { + Integer[] values = parameterMap.getRequiredArray("stringArray", Integer.class); + assertEquals(new Integer(1), values[0]); + assertEquals(new Integer(2), values[1]); + assertEquals(new Integer(3), values[2]); + } + @Test - public void testGetNumber() { - Integer value = parameterMap.getNumber("integer", Integer.class); - assertEquals(new Integer(12345), value); - } - + public void testGetNumber() { + Integer value = parameterMap.getNumber("integer", Integer.class); + assertEquals(new Integer(12345), value); + } + @Test - public void testGetRequiredNumber() { - Integer value = parameterMap.getRequiredNumber("integer", Integer.class); - assertEquals(new Integer(12345), value); - } - + public void testGetRequiredNumber() { + Integer value = parameterMap.getRequiredNumber("integer", Integer.class); + assertEquals(new Integer(12345), value); + } + @Test - public void testGetNumberWithDefault() { - Integer value = parameterMap.getNumber("bogus", Integer.class, 12345); - assertEquals(new Integer(12345), value); - } - + public void testGetNumberWithDefault() { + Integer value = parameterMap.getNumber("bogus", Integer.class, 12345); + assertEquals(new Integer(12345), value); + } + @Test - public void testGetInteger() { - Integer value = parameterMap.getInteger("integer"); - assertEquals(new Integer(12345), value); - } - + public void testGetInteger() { + Integer value = parameterMap.getInteger("integer"); + assertEquals(new Integer(12345), value); + } + @Test - public void testGetRequiredInteger() { - Integer value = parameterMap.getRequiredInteger("integer"); - assertEquals(new Integer(12345), value); - } - + public void testGetRequiredInteger() { + Integer value = parameterMap.getRequiredInteger("integer"); + assertEquals(new Integer(12345), value); + } + @Test - public void testGetIntegerWithDefault() { - Integer value = parameterMap.getInteger("bogus", 12345); - assertEquals(new Integer(12345), value); - } - + public void testGetIntegerWithDefault() { + Integer value = parameterMap.getInteger("bogus", 12345); + assertEquals(new Integer(12345), value); + } + @Test - public void testGetLong() { - Long value = parameterMap.getLong("integer"); - assertEquals(new Long(12345), value); - } - + public void testGetLong() { + Long value = parameterMap.getLong("integer"); + assertEquals(new Long(12345), value); + } + @Test - public void testGetRequiredLong() { - Long value = parameterMap.getRequiredLong("integer"); - assertEquals(new Long(12345), value); - } - + public void testGetRequiredLong() { + Long value = parameterMap.getRequiredLong("integer"); + assertEquals(new Long(12345), value); + } + @Test - public void testGetLongWithDefault() { - Long value = parameterMap.getLong("bogus", 12345L); - assertEquals(new Long(12345), value); - } - + public void testGetLongWithDefault() { + Long value = parameterMap.getLong("bogus", 12345L); + assertEquals(new Long(12345), value); + } + @Test - public void testGetBoolean() { - Boolean value = parameterMap.getBoolean("boolean"); - assertEquals(Boolean.TRUE, value); - } - + public void testGetBoolean() { + Boolean value = parameterMap.getBoolean("boolean"); + assertEquals(Boolean.TRUE, value); + } + @Test - public void testGetRequiredBoolean() { - Boolean value = parameterMap.getRequiredBoolean("boolean"); - assertEquals(Boolean.TRUE, value); - } - + public void testGetRequiredBoolean() { + Boolean value = parameterMap.getRequiredBoolean("boolean"); + assertEquals(Boolean.TRUE, value); + } + @Test - public void testGetBooleanWithDefault() { - Boolean value = parameterMap.getBoolean("bogus", true); - assertEquals(Boolean.TRUE, value); - } - + public void testGetBooleanWithDefault() { + Boolean value = parameterMap.getBoolean("bogus", true); + assertEquals(Boolean.TRUE, value); + } + @Test - public void testGetMultipart() { - MultipartFile file = parameterMap.getMultipartFile("multipartFile"); - assertNotNull(file); - } - + public void testGetMultipart() { + MultipartFile file = parameterMap.getMultipartFile("multipartFile"); + assertNotNull(file); + } + @Test - public void testGetRequiredMultipart() { - MultipartFile file = parameterMap.getRequiredMultipartFile("multipartFile"); - assertNotNull(file); - } - + public void testGetRequiredMultipart() { + MultipartFile file = parameterMap.getRequiredMultipartFile("multipartFile"); + assertNotNull(file); + } + @Test - public void testEquality() { - LocalParameterMap map1 = new LocalParameterMap(new HashMap<>(parameterMap.asMap())); - assertEquals(parameterMap, map1); - } - + public void testEquality() { + LocalParameterMap map1 = new LocalParameterMap(new HashMap<>(parameterMap.asMap())); + assertEquals(parameterMap, map1); + } + @Test - public void testAsAttributeMap() { - AttributeMap map = parameterMap.asAttributeMap(); - assertEquals(map.asMap(), parameterMap.asMap()); - } -} + public void testAsAttributeMap() { + AttributeMap map = parameterMap.asAttributeMap(); + assertEquals(map.asMap(), parameterMap.asMap()); + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/definition/registry/FlowDefinitionRegistryImplTests.java b/spring-webflow/src/test/java/org/springframework/webflow/definition/registry/FlowDefinitionRegistryImplTests.java index 8f63df2d..1e591272 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/definition/registry/FlowDefinitionRegistryImplTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/definition/registry/FlowDefinitionRegistryImplTests.java @@ -1,238 +1,238 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.definition.registry; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.context.ApplicationContext; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.StateDefinition; - -/** - * Unit tests for {@link FlowDefinitionRegistryImpl}. - */ -public class FlowDefinitionRegistryImplTests { - - private FlowDefinitionRegistryImpl registry = new FlowDefinitionRegistryImpl(); - - private FooFlow fooFlow; - - private BarFlow barFlow; - +/* + * Copyright 2004-2012 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 + * + * https://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.definition.registry; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.StateDefinition; + +/** + * Unit tests for {@link FlowDefinitionRegistryImpl}. + */ +public class FlowDefinitionRegistryImplTests { + + private FlowDefinitionRegistryImpl registry = new FlowDefinitionRegistryImpl(); + + private FooFlow fooFlow; + + private BarFlow barFlow; + @BeforeEach - public void setUp() { - fooFlow = new FooFlow(); - barFlow = new BarFlow(); - } - + public void setUp() { + fooFlow = new FooFlow(); + barFlow = new BarFlow(); + } + @Test - public void testNoSuchFlowDefinition() { - try { - registry.getFlowDefinition("bogus"); - fail("Should've bombed with NoSuchFlow"); - } catch (NoSuchFlowDefinitionException e) { - - } - } - + public void testNoSuchFlowDefinition() { + try { + registry.getFlowDefinition("bogus"); + fail("Should've bombed with NoSuchFlow"); + } catch (NoSuchFlowDefinitionException e) { + + } + } + @Test - public void testNullFlowDefinitionId() { - try { - registry.getFlowDefinition(null); - fail("Should have bombed with illegal argument"); - } catch (IllegalArgumentException e) { - - } - } - + public void testNullFlowDefinitionId() { + try { + registry.getFlowDefinition(null); + fail("Should have bombed with illegal argument"); + } catch (IllegalArgumentException e) { + + } + } + @Test - public void testBlankFlowDefinitionId() { - try { - registry.getFlowDefinition(""); - fail("Should have bombed with illegal argument"); - } catch (IllegalArgumentException e) { - - } - } - + public void testBlankFlowDefinitionId() { + try { + registry.getFlowDefinition(""); + fail("Should have bombed with illegal argument"); + } catch (IllegalArgumentException e) { + + } + } + @Test - public void testRegisterFlow() { - registry.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); - assertTrue(registry.containsFlowDefinition("foo")); - assertEquals(fooFlow, registry.getFlowDefinition("foo")); - } - + public void testRegisterFlow() { + registry.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); + assertTrue(registry.containsFlowDefinition("foo")); + assertEquals(fooFlow, registry.getFlowDefinition("foo")); + } + @Test - public void testGetFlowIds() { - registry.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); - registry.registerFlowDefinition(new StaticFlowDefinitionHolder(barFlow)); - assertEquals("bar", registry.getFlowDefinitionIds()[0]); - assertEquals("foo", registry.getFlowDefinitionIds()[1]); - } - + public void testGetFlowIds() { + registry.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); + registry.registerFlowDefinition(new StaticFlowDefinitionHolder(barFlow)); + assertEquals("bar", registry.getFlowDefinitionIds()[0]); + assertEquals("foo", registry.getFlowDefinitionIds()[1]); + } + @Test - public void testRegisterFlowSameIds() { - registry.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); - FooFlow newFlow = new FooFlow(); - registry.registerFlowDefinition(new StaticFlowDefinitionHolder(newFlow)); - assertSame(newFlow, registry.getFlowDefinition("foo")); - } - + public void testRegisterFlowSameIds() { + registry.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); + FooFlow newFlow = new FooFlow(); + registry.registerFlowDefinition(new StaticFlowDefinitionHolder(newFlow)); + assertSame(newFlow, registry.getFlowDefinition("foo")); + } + @Test - public void testRegisterMultipleFlows() { - registry.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); - registry.registerFlowDefinition(new StaticFlowDefinitionHolder(barFlow)); - assertTrue(registry.containsFlowDefinition("foo")); - assertTrue(registry.containsFlowDefinition("bar")); - assertEquals(fooFlow, registry.getFlowDefinition("foo")); - assertEquals(barFlow, registry.getFlowDefinition("bar")); - } - + public void testRegisterMultipleFlows() { + registry.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); + registry.registerFlowDefinition(new StaticFlowDefinitionHolder(barFlow)); + assertTrue(registry.containsFlowDefinition("foo")); + assertTrue(registry.containsFlowDefinition("bar")); + assertEquals(fooFlow, registry.getFlowDefinition("foo")); + assertEquals(barFlow, registry.getFlowDefinition("bar")); + } + @Test - public void testParentHierarchy() { - testRegisterMultipleFlows(); - FlowDefinitionRegistryImpl child = new FlowDefinitionRegistryImpl(); - child.setParent(registry); - FooFlow fooFlow = new FooFlow(); - child.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); - assertTrue(child.containsFlowDefinition("foo")); - assertTrue(child.containsFlowDefinition("bar")); - assertSame(fooFlow, child.getFlowDefinition("foo")); - assertEquals(barFlow, child.getFlowDefinition("bar")); - } - + public void testParentHierarchy() { + testRegisterMultipleFlows(); + FlowDefinitionRegistryImpl child = new FlowDefinitionRegistryImpl(); + child.setParent(registry); + FooFlow fooFlow = new FooFlow(); + child.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); + assertTrue(child.containsFlowDefinition("foo")); + assertTrue(child.containsFlowDefinition("bar")); + assertSame(fooFlow, child.getFlowDefinition("foo")); + assertEquals(barFlow, child.getFlowDefinition("bar")); + } + @Test - public void testDestroy() { - registry.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); - registry.registerFlowDefinition(new StaticFlowDefinitionHolder(barFlow)); - assertEquals(fooFlow, registry.getFlowDefinition("foo")); - assertEquals(barFlow, registry.getFlowDefinition("bar")); - assertFalse(fooFlow.destroyed); - assertFalse(barFlow.destroyed); - registry.destroy(); - assertTrue(fooFlow.destroyed); - assertTrue(barFlow.destroyed); - } - - private static class FooFlow implements FlowDefinition { - private String id = "foo"; - - private boolean destroyed; - - public MutableAttributeMap getAttributes() { - return null; - } - - public String getCaption() { - return null; - } - - public String getDescription() { - return null; - } - - public String getId() { - return id; - } - - public StateDefinition getStartState() { - return null; - } - - public StateDefinition getState(String id) throws IllegalArgumentException { - return null; - } - - public String[] getPossibleOutcomes() { - return null; - } - - public ClassLoader getClassLoader() { - return null; - } - - public ApplicationContext getApplicationContext() { - return null; - } - - public boolean inDevelopment() { - return false; - } - - public void destroy() { - destroyed = true; - } - - } - - private static class BarFlow implements FlowDefinition { - private String id = "bar"; - - private boolean destroyed; - - public MutableAttributeMap getAttributes() { - return null; - } - - public String getCaption() { - return null; - } - - public String getDescription() { - return null; - } - - public String getId() { - return id; - } - - public StateDefinition getStartState() { - return null; - } - - public StateDefinition getState(String id) throws IllegalArgumentException { - return null; - } - - public String[] getPossibleOutcomes() { - return null; - } - - public ClassLoader getClassLoader() { - return null; - } - - public ApplicationContext getApplicationContext() { - return null; - } - - public boolean inDevelopment() { - return false; - } - - public void destroy() { - destroyed = true; - } - - } + public void testDestroy() { + registry.registerFlowDefinition(new StaticFlowDefinitionHolder(fooFlow)); + registry.registerFlowDefinition(new StaticFlowDefinitionHolder(barFlow)); + assertEquals(fooFlow, registry.getFlowDefinition("foo")); + assertEquals(barFlow, registry.getFlowDefinition("bar")); + assertFalse(fooFlow.destroyed); + assertFalse(barFlow.destroyed); + registry.destroy(); + assertTrue(fooFlow.destroyed); + assertTrue(barFlow.destroyed); + } + + private static class FooFlow implements FlowDefinition { + private String id = "foo"; + + private boolean destroyed; + + public MutableAttributeMap getAttributes() { + return null; + } + + public String getCaption() { + return null; + } + + public String getDescription() { + return null; + } + + public String getId() { + return id; + } + + public StateDefinition getStartState() { + return null; + } + + public StateDefinition getState(String id) throws IllegalArgumentException { + return null; + } + + public String[] getPossibleOutcomes() { + return null; + } + + public ClassLoader getClassLoader() { + return null; + } + + public ApplicationContext getApplicationContext() { + return null; + } + + public boolean inDevelopment() { + return false; + } + + public void destroy() { + destroyed = true; + } + + } + + private static class BarFlow implements FlowDefinition { + private String id = "bar"; + + private boolean destroyed; + + public MutableAttributeMap getAttributes() { + return null; + } + + public String getCaption() { + return null; + } + + public String getDescription() { + return null; + } + + public String getId() { + return id; + } + + public StateDefinition getStartState() { + return null; + } + + public StateDefinition getState(String id) throws IllegalArgumentException { + return null; + } + + public String[] getPossibleOutcomes() { + return null; + } + + public ClassLoader getClassLoader() { + return null; + } + + public ApplicationContext getApplicationContext() { + return null; + } + + public boolean inDevelopment() { + return false; + } + + public void destroy() { + destroyed = true; + } + + } } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowExecutionHandlerSetTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowExecutionHandlerSetTests.java index 915ea7f1..dd3e7467 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowExecutionHandlerSetTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/FlowExecutionHandlerSetTests.java @@ -1,73 +1,73 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; -import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.test.MockRequestControlContext; - -/** - * Unit tests for {@link org.springframework.webflow.engine.FlowExecutionExceptionHandler} related code. - * - * @author Erwin Vervaet - */ -public class FlowExecutionHandlerSetTests { - - Flow flow = new Flow("myFlow"); - MockRequestControlContext context = new MockRequestControlContext(flow); - boolean handled; - +/* + * Copyright 2004-2012 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 + * + * https://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.engine; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.test.MockRequestControlContext; + +/** + * Unit tests for {@link org.springframework.webflow.engine.FlowExecutionExceptionHandler} related code. + * + * @author Erwin Vervaet + */ +public class FlowExecutionHandlerSetTests { + + Flow flow = new Flow("myFlow"); + MockRequestControlContext context = new MockRequestControlContext(flow); + boolean handled; + @Test - public void testHandleException() { - FlowExecutionExceptionHandlerSet handlerSet = new FlowExecutionExceptionHandlerSet(); - handlerSet.add(new TestStateExceptionHandler(NullPointerException.class, "null")); - handlerSet.add(new TestStateExceptionHandler(FlowExecutionException.class, "execution 1")); - handlerSet.add(new TestStateExceptionHandler(FlowExecutionException.class, "execution 2")); - assertEquals(3, handlerSet.size()); - FlowExecutionException e = new FlowExecutionException("flowId", "stateId", "Test"); - assertTrue(handlerSet.handleException(e, context)); - assertFalse(context.getFlowScope().contains("null")); - assertTrue(context.getFlowScope().contains("execution 1")); - assertFalse(context.getFlowScope().contains("execution 2")); - } - - /** - * State exception handler used in tests. - */ - public static class TestStateExceptionHandler implements FlowExecutionExceptionHandler { - - private Class typeToHandle; - private String resultName; - - public TestStateExceptionHandler(Class typeToHandle, String resultName) { - this.typeToHandle = typeToHandle; - this.resultName = resultName; - } - - public boolean canHandle(FlowExecutionException exception) { - return typeToHandle.isInstance(exception); - } - - public void handle(FlowExecutionException exception, RequestControlContext context) { - context.getFlowScope().put(resultName, true); - } - } - -} + public void testHandleException() { + FlowExecutionExceptionHandlerSet handlerSet = new FlowExecutionExceptionHandlerSet(); + handlerSet.add(new TestStateExceptionHandler(NullPointerException.class, "null")); + handlerSet.add(new TestStateExceptionHandler(FlowExecutionException.class, "execution 1")); + handlerSet.add(new TestStateExceptionHandler(FlowExecutionException.class, "execution 2")); + assertEquals(3, handlerSet.size()); + FlowExecutionException e = new FlowExecutionException("flowId", "stateId", "Test"); + assertTrue(handlerSet.handleException(e, context)); + assertFalse(context.getFlowScope().contains("null")); + assertTrue(context.getFlowScope().contains("execution 1")); + assertFalse(context.getFlowScope().contains("execution 2")); + } + + /** + * State exception handler used in tests. + */ + public static class TestStateExceptionHandler implements FlowExecutionExceptionHandler { + + private Class typeToHandle; + private String resultName; + + public TestStateExceptionHandler(Class typeToHandle, String resultName) { + this.typeToHandle = typeToHandle; + this.resultName = resultName; + } + + public boolean canHandle(FlowExecutionException exception) { + return typeToHandle.isInstance(exception); + } + + public void handle(FlowExecutionException exception, RequestControlContext context) { + context.getFlowScope().put(resultName, true); + } + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactoryTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactoryTests.java index 8bce53fe..0d4ea844 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactoryTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplFactoryTests.java @@ -1,208 +1,208 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.webflow.core.collection.LocalAttributeMap; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.definition.registry.FlowDefinitionConstructionException; -import org.springframework.webflow.definition.registry.FlowDefinitionLocator; -import org.springframework.webflow.definition.registry.NoSuchFlowDefinitionException; -import org.springframework.webflow.engine.EndState; -import org.springframework.webflow.engine.Flow; -import org.springframework.webflow.engine.RequestControlContext; -import org.springframework.webflow.engine.State; -import org.springframework.webflow.execution.FlowExecution; -import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.execution.FlowExecutionKey; -import org.springframework.webflow.execution.FlowExecutionKeyFactory; -import org.springframework.webflow.execution.FlowExecutionListener; -import org.springframework.webflow.execution.FlowSession; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader; -import org.springframework.webflow.test.MockExternalContext; -import org.springframework.webflow.test.MockFlowExecutionKey; - -/** - * Test case for {@link FlowExecutionImplFactory}. - */ -public class FlowExecutionImplFactoryTests { - - private FlowExecutionImplFactory factory = new FlowExecutionImplFactory(); - - private Flow flowDefinition; - - private boolean starting; - - private boolean getKeyCalled; - - private boolean updateSnapshotCalled; - - private boolean removeSnapshotCalled; - - private boolean removeAllSnapshotsCalled; - - @BeforeEach - public void setUp() { - flowDefinition = new Flow("flow"); - new EndState(flowDefinition, "end"); - } - +/* + * Copyright 2004-2012 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 + * + * https://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.engine.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.webflow.core.collection.LocalAttributeMap; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.definition.registry.FlowDefinitionConstructionException; +import org.springframework.webflow.definition.registry.FlowDefinitionLocator; +import org.springframework.webflow.definition.registry.NoSuchFlowDefinitionException; +import org.springframework.webflow.engine.EndState; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.engine.RequestControlContext; +import org.springframework.webflow.engine.State; +import org.springframework.webflow.execution.FlowExecution; +import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.execution.FlowExecutionKey; +import org.springframework.webflow.execution.FlowExecutionKeyFactory; +import org.springframework.webflow.execution.FlowExecutionListener; +import org.springframework.webflow.execution.FlowSession; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader; +import org.springframework.webflow.test.MockExternalContext; +import org.springframework.webflow.test.MockFlowExecutionKey; + +/** + * Test case for {@link FlowExecutionImplFactory}. + */ +public class FlowExecutionImplFactoryTests { + + private FlowExecutionImplFactory factory = new FlowExecutionImplFactory(); + + private Flow flowDefinition; + + private boolean starting; + + private boolean getKeyCalled; + + private boolean updateSnapshotCalled; + + private boolean removeSnapshotCalled; + + private boolean removeAllSnapshotsCalled; + + @BeforeEach + public void setUp() { + flowDefinition = new Flow("flow"); + new EndState(flowDefinition, "end"); + } + @Test - public void testCreate() { - FlowExecution execution = factory.createFlowExecution(flowDefinition); - assertSame(flowDefinition, execution.getDefinition()); - assertFalse(execution.hasStarted()); - assertFalse(execution.isActive()); - } - + public void testCreate() { + FlowExecution execution = factory.createFlowExecution(flowDefinition); + assertSame(flowDefinition, execution.getDefinition()); + assertFalse(execution.hasStarted()); + assertFalse(execution.isActive()); + } + @Test - public void testCreateNullArgument() { - try { - factory.createFlowExecution(null); - fail("Should've failed"); - } catch (IllegalArgumentException e) { - - } - } - + public void testCreateNullArgument() { + try { + factory.createFlowExecution(null); + fail("Should've failed"); + } catch (IllegalArgumentException e) { + + } + } + @Test - public void testCreateWithExecutionAttributes() { - MutableAttributeMap attributes = new LocalAttributeMap<>(); - attributes.put("foo", "bar"); - factory.setExecutionAttributes(attributes); - FlowExecution execution = factory.createFlowExecution(flowDefinition); - assertEquals(attributes, execution.getAttributes()); - assertSame(attributes.asMap(), execution.getAttributes().asMap(), "Flow execution attributes are global"); - } - + public void testCreateWithExecutionAttributes() { + MutableAttributeMap attributes = new LocalAttributeMap<>(); + attributes.put("foo", "bar"); + factory.setExecutionAttributes(attributes); + FlowExecution execution = factory.createFlowExecution(flowDefinition); + assertEquals(attributes, execution.getAttributes()); + assertSame(attributes.asMap(), execution.getAttributes().asMap(), "Flow execution attributes are global"); + } + @Test - public void testCreateWithExecutionListener() { - FlowExecutionListener listener1 = new FlowExecutionListener() { - public void sessionStarting(RequestContext context, FlowSession session, MutableAttributeMap input) { - starting = true; - } - }; - factory.setExecutionListenerLoader(new StaticFlowExecutionListenerLoader(listener1)); - FlowExecution execution = factory.createFlowExecution(flowDefinition); - assertFalse(execution.isActive()); - execution.start(null, new MockExternalContext()); - assertTrue(starting); - } - + public void testCreateWithExecutionListener() { + FlowExecutionListener listener1 = new FlowExecutionListener() { + public void sessionStarting(RequestContext context, FlowSession session, MutableAttributeMap input) { + starting = true; + } + }; + factory.setExecutionListenerLoader(new StaticFlowExecutionListenerLoader(listener1)); + FlowExecution execution = factory.createFlowExecution(flowDefinition); + assertFalse(execution.isActive()); + execution.start(null, new MockExternalContext()); + assertTrue(starting); + } + @Test - public void testCreateWithExecutionKeyFactory() { - State state = new State(flowDefinition, "state") { - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - context.assignFlowExecutionKey(); - context.updateCurrentFlowExecutionSnapshot(); - context.removeCurrentFlowExecutionSnapshot(); - context.removeAllFlowExecutionSnapshots(); - } - }; - flowDefinition.setStartState(state); - factory.setExecutionKeyFactory(new MockFlowExecutionKeyFactory()); - FlowExecution execution = factory.createFlowExecution(flowDefinition); - execution.start(null, new MockExternalContext()); - assertTrue(getKeyCalled); - assertTrue(removeAllSnapshotsCalled); - assertTrue(removeSnapshotCalled); - assertTrue(updateSnapshotCalled); - assertNull(execution.getKey()); - } - + public void testCreateWithExecutionKeyFactory() { + State state = new State(flowDefinition, "state") { + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + context.assignFlowExecutionKey(); + context.updateCurrentFlowExecutionSnapshot(); + context.removeCurrentFlowExecutionSnapshot(); + context.removeAllFlowExecutionSnapshots(); + } + }; + flowDefinition.setStartState(state); + factory.setExecutionKeyFactory(new MockFlowExecutionKeyFactory()); + FlowExecution execution = factory.createFlowExecution(flowDefinition); + execution.start(null, new MockExternalContext()); + assertTrue(getKeyCalled); + assertTrue(removeAllSnapshotsCalled); + assertTrue(removeSnapshotCalled); + assertTrue(updateSnapshotCalled); + assertNull(execution.getKey()); + } + @Test - public void testRestoreExecutionState() { - FlowExecutionImpl flowExecution = (FlowExecutionImpl) factory.createFlowExecution(flowDefinition); - LocalAttributeMap executionAttributes = new LocalAttributeMap<>(); - factory.setExecutionAttributes(executionAttributes); - FlowExecutionListener listener = new FlowExecutionListener() { - }; - factory.setExecutionListenerLoader(new StaticFlowExecutionListenerLoader(listener)); - MockFlowExecutionKeyFactory keyFactory = new MockFlowExecutionKeyFactory(); - factory.setExecutionKeyFactory(keyFactory); - FlowExecutionKey flowExecutionKey = new MockFlowExecutionKey("e1s1"); - LocalAttributeMap conversationScope = new LocalAttributeMap<>(); - SimpleFlowDefinitionLocator locator = new SimpleFlowDefinitionLocator(); - FlowSessionImpl session1 = new FlowSessionImpl(); - session1.setFlowId("flow"); - session1.setStateId("end"); - FlowSessionImpl session2 = new FlowSessionImpl(); - session2.setFlowId("child"); - session2.setStateId("state"); - flowExecution.getFlowSessions().add(session1); - flowExecution.getFlowSessions().add(session2); - factory.restoreFlowExecution(flowExecution, flowDefinition, flowExecutionKey, conversationScope, locator); - assertSame(flowExecution.getAttributes().asMap(), executionAttributes.asMap(), - "Flow execution attributes are global"); - assertEquals(1, flowExecution.getListeners().length); - assertSame(listener, flowExecution.getListeners()[0]); - assertSame(flowExecutionKey, flowExecution.getKey()); - assertSame(keyFactory, flowExecution.getKeyFactory()); - assertSame(conversationScope, flowExecution.getConversationScope()); - assertSame(flowExecution.getFlowSessions().get(0).getDefinition(), flowDefinition); - assertSame(flowExecution.getFlowSessions().get(0).getDefinition().getState("end"), - flowDefinition.getState("end")); - assertSame(flowExecution.getFlowSessions().get(1).getDefinition(), locator.child); - assertSame(flowExecution.getFlowSessions().get(1).getDefinition().getState("state"), - locator.child.getState("state")); - } - - private class MockFlowExecutionKeyFactory implements FlowExecutionKeyFactory { - public FlowExecutionKey getKey(FlowExecution execution) { - getKeyCalled = true; - return null; - } - - public void removeAllFlowExecutionSnapshots(FlowExecution execution) { - removeAllSnapshotsCalled = true; - } - - public void removeFlowExecutionSnapshot(FlowExecution execution) { - removeSnapshotCalled = true; - } - - public void updateFlowExecutionSnapshot(FlowExecution execution) { - updateSnapshotCalled = true; - } - } - - private class SimpleFlowDefinitionLocator implements FlowDefinitionLocator { - Flow child = new Flow("child"); - - public SimpleFlowDefinitionLocator() { - new EndState(child, "state"); - } - - public FlowDefinition getFlowDefinition(String flowId) throws NoSuchFlowDefinitionException, - FlowDefinitionConstructionException { - if (flowId.equals(child.getId())) { - return child; - } else { - throw new IllegalArgumentException(flowId.toString()); - } - } - } -} + public void testRestoreExecutionState() { + FlowExecutionImpl flowExecution = (FlowExecutionImpl) factory.createFlowExecution(flowDefinition); + LocalAttributeMap executionAttributes = new LocalAttributeMap<>(); + factory.setExecutionAttributes(executionAttributes); + FlowExecutionListener listener = new FlowExecutionListener() { + }; + factory.setExecutionListenerLoader(new StaticFlowExecutionListenerLoader(listener)); + MockFlowExecutionKeyFactory keyFactory = new MockFlowExecutionKeyFactory(); + factory.setExecutionKeyFactory(keyFactory); + FlowExecutionKey flowExecutionKey = new MockFlowExecutionKey("e1s1"); + LocalAttributeMap conversationScope = new LocalAttributeMap<>(); + SimpleFlowDefinitionLocator locator = new SimpleFlowDefinitionLocator(); + FlowSessionImpl session1 = new FlowSessionImpl(); + session1.setFlowId("flow"); + session1.setStateId("end"); + FlowSessionImpl session2 = new FlowSessionImpl(); + session2.setFlowId("child"); + session2.setStateId("state"); + flowExecution.getFlowSessions().add(session1); + flowExecution.getFlowSessions().add(session2); + factory.restoreFlowExecution(flowExecution, flowDefinition, flowExecutionKey, conversationScope, locator); + assertSame(flowExecution.getAttributes().asMap(), executionAttributes.asMap(), + "Flow execution attributes are global"); + assertEquals(1, flowExecution.getListeners().length); + assertSame(listener, flowExecution.getListeners()[0]); + assertSame(flowExecutionKey, flowExecution.getKey()); + assertSame(keyFactory, flowExecution.getKeyFactory()); + assertSame(conversationScope, flowExecution.getConversationScope()); + assertSame(flowExecution.getFlowSessions().get(0).getDefinition(), flowDefinition); + assertSame(flowExecution.getFlowSessions().get(0).getDefinition().getState("end"), + flowDefinition.getState("end")); + assertSame(flowExecution.getFlowSessions().get(1).getDefinition(), locator.child); + assertSame(flowExecution.getFlowSessions().get(1).getDefinition().getState("state"), + locator.child.getState("state")); + } + + private class MockFlowExecutionKeyFactory implements FlowExecutionKeyFactory { + public FlowExecutionKey getKey(FlowExecution execution) { + getKeyCalled = true; + return null; + } + + public void removeAllFlowExecutionSnapshots(FlowExecution execution) { + removeAllSnapshotsCalled = true; + } + + public void removeFlowExecutionSnapshot(FlowExecution execution) { + removeSnapshotCalled = true; + } + + public void updateFlowExecutionSnapshot(FlowExecution execution) { + updateSnapshotCalled = true; + } + } + + private class SimpleFlowDefinitionLocator implements FlowDefinitionLocator { + Flow child = new Flow("child"); + + public SimpleFlowDefinitionLocator() { + new EndState(child, "state"); + } + + public FlowDefinition getFlowDefinition(String flowId) throws NoSuchFlowDefinitionException, + FlowDefinitionConstructionException { + if (flowId.equals(child.getId())) { + return child; + } else { + throw new IllegalArgumentException(flowId.toString()); + } + } + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java index 5e98f17d..38b758fd 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/impl/FlowExecutionImplTests.java @@ -1,502 +1,502 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.impl; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import org.junit.jupiter.api.Test; -import org.springframework.binding.message.MessageBuilder; -import org.springframework.webflow.core.collection.MutableAttributeMap; -import org.springframework.webflow.definition.FlowDefinition; -import org.springframework.webflow.engine.EndState; -import org.springframework.webflow.engine.Flow; -import org.springframework.webflow.engine.FlowExecutionExceptionHandler; -import org.springframework.webflow.engine.RequestControlContext; -import org.springframework.webflow.engine.State; -import org.springframework.webflow.engine.StubViewFactory; -import org.springframework.webflow.engine.Transition; -import org.springframework.webflow.engine.ViewState; -import org.springframework.webflow.engine.support.DefaultTargetStateResolver; -import org.springframework.webflow.execution.FlowExecutionException; -import org.springframework.webflow.execution.FlowExecutionListener; -import org.springframework.webflow.execution.FlowSession; -import org.springframework.webflow.execution.MockFlowExecutionListener; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.execution.RequestContextHolder; -import org.springframework.webflow.test.MockExternalContext; -import org.springframework.webflow.test.MockFlowExecutionKeyFactory; - -/** - * General flow execution tests. - * - * @author Keith Donald - * @author Erwin Vervaet - * @author Ben Hale - * @author Jeremy Grelle - */ -public class FlowExecutionImplTests { - - +/* + * Copyright 2004-2012 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 + * + * https://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.engine.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.Test; +import org.springframework.binding.message.MessageBuilder; +import org.springframework.webflow.core.collection.MutableAttributeMap; +import org.springframework.webflow.definition.FlowDefinition; +import org.springframework.webflow.engine.EndState; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.engine.FlowExecutionExceptionHandler; +import org.springframework.webflow.engine.RequestControlContext; +import org.springframework.webflow.engine.State; +import org.springframework.webflow.engine.StubViewFactory; +import org.springframework.webflow.engine.Transition; +import org.springframework.webflow.engine.ViewState; +import org.springframework.webflow.engine.support.DefaultTargetStateResolver; +import org.springframework.webflow.execution.FlowExecutionException; +import org.springframework.webflow.execution.FlowExecutionListener; +import org.springframework.webflow.execution.FlowSession; +import org.springframework.webflow.execution.MockFlowExecutionListener; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.execution.RequestContextHolder; +import org.springframework.webflow.test.MockExternalContext; +import org.springframework.webflow.test.MockFlowExecutionKeyFactory; + +/** + * General flow execution tests. + * + * @author Keith Donald + * @author Erwin Vervaet + * @author Ben Hale + * @author Jeremy Grelle + */ +public class FlowExecutionImplTests { + + @Test - public void testStartAndEnd() { - Flow flow = new Flow("flow"); - new EndState(flow, "end"); - MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); - FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setListeners(listeners); - MockExternalContext context = new MockExternalContext(); - assertFalse(execution.hasStarted()); - execution.start(null, context); - assertTrue(execution.hasStarted()); - assertFalse(execution.isActive()); - assertTrue(execution.hasEnded()); - try { - execution.getActiveSession(); - fail("should have failed"); - } catch (IllegalStateException e) { - - } - assertEquals(1, mockListener.getRequestsSubmittedCount()); - assertEquals(1, mockListener.getRequestsProcessedCount()); - assertEquals(1, mockListener.getSessionCreatingCount()); - assertEquals(1, mockListener.getSessionStartingCount()); - assertEquals(1, mockListener.getSessionStartedCount()); - assertEquals(1, mockListener.getStateEnteringCount()); - assertEquals(1, mockListener.getStateEnteredCount()); - assertEquals(1, mockListener.getSessionEndingCount()); - assertEquals(1, mockListener.getSessionEndedCount()); - assertEquals(0, mockListener.getEventSignaledCount()); - assertEquals(0, mockListener.getTransitionExecutingCount()); - assertEquals(0, mockListener.getPausedCount()); - assertEquals(0, mockListener.getResumingCount()); - assertEquals(0, mockListener.getExceptionThrownCount()); - assertEquals(0, mockListener.getFlowNestingLevel()); - } - + public void testStartAndEnd() { + Flow flow = new Flow("flow"); + new EndState(flow, "end"); + MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); + FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setListeners(listeners); + MockExternalContext context = new MockExternalContext(); + assertFalse(execution.hasStarted()); + execution.start(null, context); + assertTrue(execution.hasStarted()); + assertFalse(execution.isActive()); + assertTrue(execution.hasEnded()); + try { + execution.getActiveSession(); + fail("should have failed"); + } catch (IllegalStateException e) { + + } + assertEquals(1, mockListener.getRequestsSubmittedCount()); + assertEquals(1, mockListener.getRequestsProcessedCount()); + assertEquals(1, mockListener.getSessionCreatingCount()); + assertEquals(1, mockListener.getSessionStartingCount()); + assertEquals(1, mockListener.getSessionStartedCount()); + assertEquals(1, mockListener.getStateEnteringCount()); + assertEquals(1, mockListener.getStateEnteredCount()); + assertEquals(1, mockListener.getSessionEndingCount()); + assertEquals(1, mockListener.getSessionEndedCount()); + assertEquals(0, mockListener.getEventSignaledCount()); + assertEquals(0, mockListener.getTransitionExecutingCount()); + assertEquals(0, mockListener.getPausedCount()); + assertEquals(0, mockListener.getResumingCount()); + assertEquals(0, mockListener.getExceptionThrownCount()); + assertEquals(0, mockListener.getFlowNestingLevel()); + } + @Test - public void testStartAndEndSavedMessages() { - Flow flow = new Flow("flow"); - new EndState(flow, "end"); - MockFlowExecutionListener mockListener = new MockFlowExecutionListener() { - public void sessionStarting(RequestContext context, FlowSession session, MutableAttributeMap input) { - super.sessionStarting(context, session, input); - context.getMessageContext().addMessage(new MessageBuilder().source("foo").defaultText("bar").build()); - } - }; - FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setListeners(listeners); - MockExternalContext context = new MockExternalContext(); - assertFalse(execution.hasStarted()); - execution.start(null, context); - assertTrue(execution.hasStarted()); - assertFalse(execution.isActive()); - assertTrue(execution.hasEnded()); - assertNotNull(execution.getFlashScope().get("messagesMemento")); - } - + public void testStartAndEndSavedMessages() { + Flow flow = new Flow("flow"); + new EndState(flow, "end"); + MockFlowExecutionListener mockListener = new MockFlowExecutionListener() { + public void sessionStarting(RequestContext context, FlowSession session, MutableAttributeMap input) { + super.sessionStarting(context, session, input); + context.getMessageContext().addMessage(new MessageBuilder().source("foo").defaultText("bar").build()); + } + }; + FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setListeners(listeners); + MockExternalContext context = new MockExternalContext(); + assertFalse(execution.hasStarted()); + execution.start(null, context); + assertTrue(execution.hasStarted()); + assertFalse(execution.isActive()); + assertTrue(execution.hasEnded()); + assertNotNull(execution.getFlashScope().get("messagesMemento")); + } + @Test - public void testStartAndPause() { - Flow flow = new Flow("flow"); - new State(flow, "state") { - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - // no op - } - }; - MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); - FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setListeners(listeners); - MockExternalContext context = new MockExternalContext(); - execution.start(null, context); - assertTrue(execution.isActive()); - assertEquals(1, mockListener.getPausedCount()); - } - + public void testStartAndPause() { + Flow flow = new Flow("flow"); + new State(flow, "state") { + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + // no op + } + }; + MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); + FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setListeners(listeners); + MockExternalContext context = new MockExternalContext(); + execution.start(null, context); + assertTrue(execution.isActive()); + assertEquals(1, mockListener.getPausedCount()); + } + @Test - public void testStartWithNullInputMap() { - Flow flow = new Flow("flow"); - new State(flow, "state") { - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - // no op - } - }; - MockFlowExecutionListener mockListener = new MockFlowExecutionListener() { - public void sessionStarting(RequestContext context, FlowSession session, MutableAttributeMap input) { - super.sessionStarting(context, session, input); - assertNotNull(input); - } - }; - FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setListeners(listeners); - MockExternalContext context = new MockExternalContext(); - execution.start(null, context); - assertTrue(execution.isActive()); - assertEquals(1, mockListener.getPausedCount()); - } - + public void testStartWithNullInputMap() { + Flow flow = new Flow("flow"); + new State(flow, "state") { + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + // no op + } + }; + MockFlowExecutionListener mockListener = new MockFlowExecutionListener() { + public void sessionStarting(RequestContext context, FlowSession session, MutableAttributeMap input) { + super.sessionStarting(context, session, input); + assertNotNull(input); + } + }; + FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setListeners(listeners); + MockExternalContext context = new MockExternalContext(); + execution.start(null, context); + assertTrue(execution.isActive()); + assertEquals(1, mockListener.getPausedCount()); + } + @Test - public void testStartExceptionThrownBeforeFirstSessionCreated() { - Flow flow = new Flow("flow"); - flow.getExceptionHandlerSet().add(new FlowExecutionExceptionHandler() { - public boolean canHandle(FlowExecutionException exception) { - return true; - } - - public void handle(FlowExecutionException exception, RequestControlContext context) { - throw new UnsupportedOperationException("Should not be called"); - } - - }); - new EndState(flow, "end"); - FlowExecutionListener mockListener = new FlowExecutionListener() { - public void sessionCreating(RequestContext context, FlowDefinition definition) { - assertFalse(context.getFlowExecutionContext().isActive()); - throw new IllegalStateException("Oops"); - } - }; - FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setListeners(listeners); - MockExternalContext context = new MockExternalContext(); - assertFalse(execution.hasStarted()); - try { - execution.start(null, context); - fail("Should have failed"); - } catch (FlowExecutionException e) { - assertEquals(flow.getId(), e.getFlowId()); - assertNull(e.getStateId()); - assertTrue(e.getCause() instanceof IllegalStateException); - e.printStackTrace(); - assertTrue(e.getCause().getMessage().equals("Oops")); - } - } - + public void testStartExceptionThrownBeforeFirstSessionCreated() { + Flow flow = new Flow("flow"); + flow.getExceptionHandlerSet().add(new FlowExecutionExceptionHandler() { + public boolean canHandle(FlowExecutionException exception) { + return true; + } + + public void handle(FlowExecutionException exception, RequestControlContext context) { + throw new UnsupportedOperationException("Should not be called"); + } + + }); + new EndState(flow, "end"); + FlowExecutionListener mockListener = new FlowExecutionListener() { + public void sessionCreating(RequestContext context, FlowDefinition definition) { + assertFalse(context.getFlowExecutionContext().isActive()); + throw new IllegalStateException("Oops"); + } + }; + FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setListeners(listeners); + MockExternalContext context = new MockExternalContext(); + assertFalse(execution.hasStarted()); + try { + execution.start(null, context); + fail("Should have failed"); + } catch (FlowExecutionException e) { + assertEquals(flow.getId(), e.getFlowId()); + assertNull(e.getStateId()); + assertTrue(e.getCause() instanceof IllegalStateException); + e.printStackTrace(); + assertTrue(e.getCause().getMessage().equals("Oops")); + } + } + @Test - public void testStartExceptionThrownByState() { - Flow flow = new Flow("flow"); - State state = new State(flow, "state") { - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - throw new IllegalStateException("Oops"); - } - }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - MockExternalContext context = new MockExternalContext(); - assertFalse(execution.hasStarted()); - try { - execution.start(null, context); - fail("Should have failed"); - } catch (FlowExecutionException e) { - assertEquals(flow.getId(), e.getFlowId()); - assertEquals(state.getId(), e.getStateId()); - } - } - + public void testStartExceptionThrownByState() { + Flow flow = new Flow("flow"); + State state = new State(flow, "state") { + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + throw new IllegalStateException("Oops"); + } + }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + MockExternalContext context = new MockExternalContext(); + assertFalse(execution.hasStarted()); + try { + execution.start(null, context); + fail("Should have failed"); + } catch (FlowExecutionException e) { + assertEquals(flow.getId(), e.getFlowId()); + assertEquals(state.getId(), e.getStateId()); + } + } + @Test - public void testStartFlowExecutionExceptionThrownByState() { - Flow flow = new Flow("flow"); - final FlowExecutionException e = new FlowExecutionException("flow", "state", "Oops"); - new State(flow, "state") { - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - throw e; - } - }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - MockExternalContext context = new MockExternalContext(); - assertFalse(execution.hasStarted()); - try { - execution.start(null, context); - fail("Should have failed"); - } catch (FlowExecutionException ex) { - assertSame(e, ex); - } - } - + public void testStartFlowExecutionExceptionThrownByState() { + Flow flow = new Flow("flow"); + final FlowExecutionException e = new FlowExecutionException("flow", "state", "Oops"); + new State(flow, "state") { + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + throw e; + } + }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + MockExternalContext context = new MockExternalContext(); + assertFalse(execution.hasStarted()); + try { + execution.start(null, context); + fail("Should have failed"); + } catch (FlowExecutionException ex) { + assertSame(e, ex); + } + } + @Test - public void testStartExceptionThrownByStateHandledByFlowExceptionHandler() { - Flow flow = new Flow("flow"); - StubFlowExecutionExceptionHandler exceptionHandler = new StubFlowExecutionExceptionHandler(); - flow.getExceptionHandlerSet().add(exceptionHandler); - final FlowExecutionException e = new FlowExecutionException("flow", "state", "Oops"); - new State(flow, "state") { - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - throw e; - } - }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - MockExternalContext context = new MockExternalContext(); - assertFalse(execution.hasStarted()); - execution.start(null, context); - assertTrue(exceptionHandler.getHandled()); - } - + public void testStartExceptionThrownByStateHandledByFlowExceptionHandler() { + Flow flow = new Flow("flow"); + StubFlowExecutionExceptionHandler exceptionHandler = new StubFlowExecutionExceptionHandler(); + flow.getExceptionHandlerSet().add(exceptionHandler); + final FlowExecutionException e = new FlowExecutionException("flow", "state", "Oops"); + new State(flow, "state") { + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + throw e; + } + }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + MockExternalContext context = new MockExternalContext(); + assertFalse(execution.hasStarted()); + execution.start(null, context); + assertTrue(exceptionHandler.getHandled()); + } + @Test - public void testStartExceptionThrownByStateHandledByStateExceptionHandler() { - Flow flow = new Flow("flow"); - flow.getExceptionHandlerSet().add(new StubFlowExecutionExceptionHandler()); - final FlowExecutionException e = new FlowExecutionException("flow", "state", "Oops"); - State s = new State(flow, "state") { - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - throw e; - } - }; - StubFlowExecutionExceptionHandler exceptionHandler = new StubFlowExecutionExceptionHandler(); - s.getExceptionHandlerSet().add(exceptionHandler); - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - MockExternalContext context = new MockExternalContext(); - assertFalse(execution.hasStarted()); - execution.start(null, context); - assertTrue(exceptionHandler.getHandled()); - } - + public void testStartExceptionThrownByStateHandledByStateExceptionHandler() { + Flow flow = new Flow("flow"); + flow.getExceptionHandlerSet().add(new StubFlowExecutionExceptionHandler()); + final FlowExecutionException e = new FlowExecutionException("flow", "state", "Oops"); + State s = new State(flow, "state") { + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + throw e; + } + }; + StubFlowExecutionExceptionHandler exceptionHandler = new StubFlowExecutionExceptionHandler(); + s.getExceptionHandlerSet().add(exceptionHandler); + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + MockExternalContext context = new MockExternalContext(); + assertFalse(execution.hasStarted()); + execution.start(null, context); + assertTrue(exceptionHandler.getHandled()); + } + @Test - public void testExceptionHandledByNestedExceptionHandler() { - Flow flow = new Flow("flow"); - ExceptionThrowingExceptionHandler exceptionHandler = new ExceptionThrowingExceptionHandler(true); - flow.getExceptionHandlerSet().add(exceptionHandler); - new State(flow, "state") { - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - throw new FlowExecutionException("flow", "state", "Oops"); - } - }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - MockExternalContext context = new MockExternalContext(); - assertFalse(execution.hasStarted()); - execution.start(null, context); - assertEquals(2, exceptionHandler.getHandleCount()); - } - + public void testExceptionHandledByNestedExceptionHandler() { + Flow flow = new Flow("flow"); + ExceptionThrowingExceptionHandler exceptionHandler = new ExceptionThrowingExceptionHandler(true); + flow.getExceptionHandlerSet().add(exceptionHandler); + new State(flow, "state") { + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + throw new FlowExecutionException("flow", "state", "Oops"); + } + }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + MockExternalContext context = new MockExternalContext(); + assertFalse(execution.hasStarted()); + execution.start(null, context); + assertEquals(2, exceptionHandler.getHandleCount()); + } + @Test - public void testStartCannotCallTwice() { - Flow flow = new Flow("flow"); - new EndState(flow, "end"); - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - MockExternalContext context = new MockExternalContext(); - execution.start(null, context); - try { - execution.start(null, context); - fail("Should've failed"); - } catch (IllegalStateException e) { - - } - } - + public void testStartCannotCallTwice() { + Flow flow = new Flow("flow"); + new EndState(flow, "end"); + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + MockExternalContext context = new MockExternalContext(); + execution.start(null, context); + try { + execution.start(null, context); + fail("Should've failed"); + } catch (IllegalStateException e) { + + } + } + @Test - public void testResume() { - Flow flow = new Flow("flow"); - new ViewState(flow, "view", new StubViewFactory()); - MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); - FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setListeners(listeners); - execution.setKeyFactory(new MockFlowExecutionKeyFactory()); - MockExternalContext context = new MockExternalContext(); - execution.start(null, context); - context = new MockExternalContext(); - execution.resume(context); - assertEquals(1, mockListener.getResumingCount()); - assertEquals(2, mockListener.getPausedCount()); - } - + public void testResume() { + Flow flow = new Flow("flow"); + new ViewState(flow, "view", new StubViewFactory()); + MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); + FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setListeners(listeners); + execution.setKeyFactory(new MockFlowExecutionKeyFactory()); + MockExternalContext context = new MockExternalContext(); + execution.start(null, context); + context = new MockExternalContext(); + execution.resume(context); + assertEquals(1, mockListener.getResumingCount()); + assertEquals(2, mockListener.getPausedCount()); + } + @Test - public void testResumeNotAViewState() { - Flow flow = new Flow("flow"); - new State(flow, "state") { - protected void doEnter(RequestControlContext context) throws FlowExecutionException { - // no-op - } - }; - MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); - FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setListeners(listeners); - MockExternalContext context = new MockExternalContext(); - execution.start(null, context); - context = new MockExternalContext(); - try { - execution.resume(context); - assertEquals(1, mockListener.getResumingCount()); - fail("Should have failed"); - } catch (FlowExecutionException e) { - - } - } - + public void testResumeNotAViewState() { + Flow flow = new Flow("flow"); + new State(flow, "state") { + protected void doEnter(RequestControlContext context) throws FlowExecutionException { + // no-op + } + }; + MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); + FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setListeners(listeners); + MockExternalContext context = new MockExternalContext(); + execution.start(null, context); + context = new MockExternalContext(); + try { + execution.resume(context); + assertEquals(1, mockListener.getResumingCount()); + fail("Should have failed"); + } catch (FlowExecutionException e) { + + } + } + @Test - public void testResumeAfterEnding() { - Flow flow = new Flow("flow"); - new EndState(flow, "end"); - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - MockExternalContext context = new MockExternalContext(); - execution.start(null, context); - try { - execution.resume(context); - fail("Should've failed"); - } catch (IllegalStateException e) { - - } - } - + public void testResumeAfterEnding() { + Flow flow = new Flow("flow"); + new EndState(flow, "end"); + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + MockExternalContext context = new MockExternalContext(); + execution.start(null, context); + try { + execution.resume(context); + fail("Should've failed"); + } catch (IllegalStateException e) { + + } + } + @Test - public void testResumeException() { - Flow flow = new Flow("flow"); - ViewState state = new ViewState(flow, "view", new StubViewFactory()) { - public void resume(RequestControlContext context) { - throw new IllegalStateException("Oops"); - } - }; - MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); - FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setListeners(listeners); - execution.setKeyFactory(new MockFlowExecutionKeyFactory()); - MockExternalContext context = new MockExternalContext(); - execution.start(null, context); - context = new MockExternalContext(); - try { - execution.resume(context); - } catch (FlowExecutionException e) { - assertEquals(flow.getId(), e.getFlowId()); - assertEquals(state.getId(), e.getStateId()); - assertEquals(1, mockListener.getResumingCount()); - assertEquals(2, mockListener.getPausedCount()); - } - } - + public void testResumeException() { + Flow flow = new Flow("flow"); + ViewState state = new ViewState(flow, "view", new StubViewFactory()) { + public void resume(RequestControlContext context) { + throw new IllegalStateException("Oops"); + } + }; + MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); + FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setListeners(listeners); + execution.setKeyFactory(new MockFlowExecutionKeyFactory()); + MockExternalContext context = new MockExternalContext(); + execution.start(null, context); + context = new MockExternalContext(); + try { + execution.resume(context); + } catch (FlowExecutionException e) { + assertEquals(flow.getId(), e.getFlowId()); + assertEquals(state.getId(), e.getStateId()); + assertEquals(1, mockListener.getResumingCount()); + assertEquals(2, mockListener.getPausedCount()); + } + } + @Test - public void testResumeFlowExecutionException() { - Flow flow = new Flow("flow"); - ViewState state = new ViewState(flow, "view", new StubViewFactory()) { - public void resume(RequestControlContext context) { - throw new FlowExecutionException("flow", "view", "oops"); - } - }; - MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); - FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setListeners(listeners); - execution.setKeyFactory(new MockFlowExecutionKeyFactory()); - MockExternalContext context = new MockExternalContext(); - execution.start(null, context); - context = new MockExternalContext(); - try { - execution.resume(context); - } catch (FlowExecutionException e) { - assertEquals(flow.getId(), e.getFlowId()); - assertEquals(state.getId(), e.getStateId()); - assertEquals(1, mockListener.getResumingCount()); - assertEquals(2, mockListener.getPausedCount()); - } - } - + public void testResumeFlowExecutionException() { + Flow flow = new Flow("flow"); + ViewState state = new ViewState(flow, "view", new StubViewFactory()) { + public void resume(RequestControlContext context) { + throw new FlowExecutionException("flow", "view", "oops"); + } + }; + MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); + FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setListeners(listeners); + execution.setKeyFactory(new MockFlowExecutionKeyFactory()); + MockExternalContext context = new MockExternalContext(); + execution.start(null, context); + context = new MockExternalContext(); + try { + execution.resume(context); + } catch (FlowExecutionException e) { + assertEquals(flow.getId(), e.getFlowId()); + assertEquals(state.getId(), e.getStateId()); + assertEquals(1, mockListener.getResumingCount()); + assertEquals(2, mockListener.getPausedCount()); + } + } + @Test - public void testExecuteTransition() { - Flow flow = new Flow("flow"); - ViewState state = new ViewState(flow, "view", new StubViewFactory()) { - public void resume(RequestControlContext context) { - context.execute(getRequiredTransition(context)); - } - }; - state.getTransitionSet().add(new Transition(new DefaultTargetStateResolver("finish"))); - new EndState(flow, "finish"); - MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); - FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setListeners(listeners); - execution.setKeyFactory(new MockFlowExecutionKeyFactory()); - MockExternalContext context = new MockExternalContext(); - execution.start(null, context); - assertEquals(0, mockListener.getTransitionExecutingCount()); - execution.resume(context); - assertTrue(execution.hasEnded()); - assertEquals(1, mockListener.getTransitionExecutingCount()); - } - + public void testExecuteTransition() { + Flow flow = new Flow("flow"); + ViewState state = new ViewState(flow, "view", new StubViewFactory()) { + public void resume(RequestControlContext context) { + context.execute(getRequiredTransition(context)); + } + }; + state.getTransitionSet().add(new Transition(new DefaultTargetStateResolver("finish"))); + new EndState(flow, "finish"); + MockFlowExecutionListener mockListener = new MockFlowExecutionListener(); + FlowExecutionListener[] listeners = new FlowExecutionListener[] { mockListener }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setListeners(listeners); + execution.setKeyFactory(new MockFlowExecutionKeyFactory()); + MockExternalContext context = new MockExternalContext(); + execution.start(null, context); + assertEquals(0, mockListener.getTransitionExecutingCount()); + execution.resume(context); + assertTrue(execution.hasEnded()); + assertEquals(1, mockListener.getTransitionExecutingCount()); + } + @Test - public void testRequestContextManagedOnStartAndResume() { - Flow flow = new Flow("flow"); - new ViewState(flow, "view", new StubViewFactory()) { - public void resume(RequestControlContext context) { - assertSame(context, RequestContextHolder.getRequestContext()); - } - }; - FlowExecutionImpl execution = new FlowExecutionImpl(flow); - execution.setKeyFactory(new MockFlowExecutionKeyFactory()); - - MockExternalContext context = new MockExternalContext(); - execution.start(null, context); - assertNull(RequestContextHolder.getRequestContext(), "RequestContext was not released"); - - context = new MockExternalContext(); - execution.resume(context); - assertNull(RequestContextHolder.getRequestContext(), "RequestContext was not released"); - - } - - private static class StubFlowExecutionExceptionHandler implements FlowExecutionExceptionHandler { - - private boolean handled; - - public boolean getHandled() { - return handled; - } - - public boolean canHandle(FlowExecutionException exception) { - return true; - } - - public void handle(FlowExecutionException exception, RequestControlContext context) { - handled = true; - } - } - - private static class ExceptionThrowingExceptionHandler implements FlowExecutionExceptionHandler { - - private boolean throwOnlyOnce = true; - private int handleCount; - - public ExceptionThrowingExceptionHandler(boolean throwOnlyOnce) { - this.throwOnlyOnce = throwOnlyOnce; - } - - public int getHandleCount() { - return handleCount; - } - - public boolean canHandle(FlowExecutionException exception) { - return true; - } - - public void handle(FlowExecutionException exception, RequestControlContext context) { - this.handleCount++; - if (throwOnlyOnce && "nested exception".equals(exception.getMessage())) { - // No more exceptions - } else { - throw new FlowExecutionException(exception.getFlowId(), exception.getStateId(), "nested exception"); - } - } - - } - -} + public void testRequestContextManagedOnStartAndResume() { + Flow flow = new Flow("flow"); + new ViewState(flow, "view", new StubViewFactory()) { + public void resume(RequestControlContext context) { + assertSame(context, RequestContextHolder.getRequestContext()); + } + }; + FlowExecutionImpl execution = new FlowExecutionImpl(flow); + execution.setKeyFactory(new MockFlowExecutionKeyFactory()); + + MockExternalContext context = new MockExternalContext(); + execution.start(null, context); + assertNull(RequestContextHolder.getRequestContext(), "RequestContext was not released"); + + context = new MockExternalContext(); + execution.resume(context); + assertNull(RequestContextHolder.getRequestContext(), "RequestContext was not released"); + + } + + private static class StubFlowExecutionExceptionHandler implements FlowExecutionExceptionHandler { + + private boolean handled; + + public boolean getHandled() { + return handled; + } + + public boolean canHandle(FlowExecutionException exception) { + return true; + } + + public void handle(FlowExecutionException exception, RequestControlContext context) { + handled = true; + } + } + + private static class ExceptionThrowingExceptionHandler implements FlowExecutionExceptionHandler { + + private boolean throwOnlyOnce = true; + private int handleCount; + + public ExceptionThrowingExceptionHandler(boolean throwOnlyOnce) { + this.throwOnlyOnce = throwOnlyOnce; + } + + public int getHandleCount() { + return handleCount; + } + + public boolean canHandle(FlowExecutionException exception) { + return true; + } + + public void handle(FlowExecutionException exception, RequestControlContext context) { + this.handleCount++; + if (throwOnlyOnce && "nested exception".equals(exception.getMessage())) { + // No more exceptions + } else { + throw new FlowExecutionException(exception.getFlowId(), exception.getStateId(), "nested exception"); + } + } + + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/support/NotTransitionCriteriaTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/support/NotTransitionCriteriaTests.java index 16127cbc..d42f94a2 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/support/NotTransitionCriteriaTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/support/NotTransitionCriteriaTests.java @@ -1,46 +1,46 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.support; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.fail; - -import org.junit.jupiter.api.Test; -import org.springframework.webflow.engine.WildcardTransitionCriteria; -import org.springframework.webflow.test.MockRequestContext; - -/** - * Unit tests for {@link NotTransitionCriteria}. - * - * @author Erwin Vervaet - */ -public class NotTransitionCriteriaTests { - +/* + * Copyright 2004-2012 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 + * + * https://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.engine.support; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.Test; +import org.springframework.webflow.engine.WildcardTransitionCriteria; +import org.springframework.webflow.test.MockRequestContext; + +/** + * Unit tests for {@link NotTransitionCriteria}. + * + * @author Erwin Vervaet + */ +public class NotTransitionCriteriaTests { + @Test - public void testNull() { - try { - new NotTransitionCriteria(null); - fail(); - } catch (IllegalArgumentException e) { - } - } - + public void testNull() { + try { + new NotTransitionCriteria(null); + fail(); + } catch (IllegalArgumentException e) { + } + } + @Test - public void testNegation() { - assertFalse(new NotTransitionCriteria(WildcardTransitionCriteria.INSTANCE).test(new MockRequestContext())); - } - -} + public void testNegation() { + assertFalse(new NotTransitionCriteria(WildcardTransitionCriteria.INSTANCE).test(new MockRequestContext())); + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/support/TransitionCriteriaChainTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/support/TransitionCriteriaChainTests.java index ecc9eab7..0721f1c7 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/support/TransitionCriteriaChainTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/support/TransitionCriteriaChainTests.java @@ -1,125 +1,125 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.engine.support; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.webflow.action.EventFactorySupport; -import org.springframework.webflow.engine.TransitionCriteria; -import org.springframework.webflow.execution.Action; -import org.springframework.webflow.execution.AnnotatedAction; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.test.MockRequestContext; - -/** - * Unit tests for {@link TransitionCriteriaChain}. - * - * @author Erwin Vervaet - */ -public class TransitionCriteriaChainTests { - - private TransitionCriteriaChain chain; - private MockRequestContext context; - +/* + * Copyright 2004-2012 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 + * + * https://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.engine.support; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.webflow.action.EventFactorySupport; +import org.springframework.webflow.engine.TransitionCriteria; +import org.springframework.webflow.execution.Action; +import org.springframework.webflow.execution.AnnotatedAction; +import org.springframework.webflow.execution.Event; +import org.springframework.webflow.execution.RequestContext; +import org.springframework.webflow.test.MockRequestContext; + +/** + * Unit tests for {@link TransitionCriteriaChain}. + * + * @author Erwin Vervaet + */ +public class TransitionCriteriaChainTests { + + private TransitionCriteriaChain chain; + private MockRequestContext context; + @BeforeEach - public void setUp() throws Exception { - chain = new TransitionCriteriaChain(); - context = new MockRequestContext(); - } - + public void setUp() throws Exception { + chain = new TransitionCriteriaChain(); + context = new MockRequestContext(); + } + @Test - public void testEmptyChain() { - assertTrue(chain.test(context)); - } - + public void testEmptyChain() { + assertTrue(chain.test(context)); + } + @Test - public void testAllTrue() { - TestTransitionCriteria criteria1 = new TestTransitionCriteria(true); - TestTransitionCriteria criteria2 = new TestTransitionCriteria(true); - TestTransitionCriteria criteria3 = new TestTransitionCriteria(true); - chain.add(criteria1); - chain.add(criteria2); - chain.add(criteria3); - assertTrue(chain.test(context)); - assertTrue(criteria1.tested); - assertTrue(criteria2.tested); - assertTrue(criteria3.tested); - } - + public void testAllTrue() { + TestTransitionCriteria criteria1 = new TestTransitionCriteria(true); + TestTransitionCriteria criteria2 = new TestTransitionCriteria(true); + TestTransitionCriteria criteria3 = new TestTransitionCriteria(true); + chain.add(criteria1); + chain.add(criteria2); + chain.add(criteria3); + assertTrue(chain.test(context)); + assertTrue(criteria1.tested); + assertTrue(criteria2.tested); + assertTrue(criteria3.tested); + } + @Test - public void testWithFalse() { - TestTransitionCriteria criteria1 = new TestTransitionCriteria(true); - TestTransitionCriteria criteria2 = new TestTransitionCriteria(false); - TestTransitionCriteria criteria3 = new TestTransitionCriteria(true); - chain.add(criteria1); - chain.add(criteria2); - chain.add(criteria3); - assertFalse(chain.test(context)); - assertTrue(criteria1.tested); - assertTrue(criteria2.tested); - assertFalse(criteria3.tested); - } - + public void testWithFalse() { + TestTransitionCriteria criteria1 = new TestTransitionCriteria(true); + TestTransitionCriteria criteria2 = new TestTransitionCriteria(false); + TestTransitionCriteria criteria3 = new TestTransitionCriteria(true); + chain.add(criteria1); + chain.add(criteria2); + chain.add(criteria3); + assertFalse(chain.test(context)); + assertTrue(criteria1.tested); + assertTrue(criteria2.tested); + assertFalse(criteria3.tested); + } + @Test - public void testCriteriaChainForNoActions() { - TransitionCriteria actionChain = TransitionCriteriaChain.criteriaChainFor((Action[]) null); - assertTrue(actionChain.test(context)); - } - + public void testCriteriaChainForNoActions() { + TransitionCriteria actionChain = TransitionCriteriaChain.criteriaChainFor((Action[]) null); + assertTrue(actionChain.test(context)); + } + @Test - public void testCriteriaChainForActions() { - AnnotatedAction[] actions = new AnnotatedAction[] { new AnnotatedAction(new TestAction(true)), - new AnnotatedAction(new TestAction(false)) }; - TransitionCriteria actionChain = TransitionCriteriaChain.criteriaChainFor(actions); - assertFalse(actionChain.test(context)); - } - - private static class TestTransitionCriteria implements TransitionCriteria { - - public boolean tested = false; - private boolean result; - - public TestTransitionCriteria(boolean result) { - this.result = result; - } - - public boolean test(RequestContext context) { - tested = true; - return result; - } - } - - private static class TestAction implements Action { - - private boolean result; - - public TestAction(boolean result) { - this.result = result; - } - - public Event execute(RequestContext context) throws Exception { - if (result) { - return new EventFactorySupport().success(this); - } else { - return new EventFactorySupport().error(this); - } - } - } -} + public void testCriteriaChainForActions() { + AnnotatedAction[] actions = new AnnotatedAction[] { new AnnotatedAction(new TestAction(true)), + new AnnotatedAction(new TestAction(false)) }; + TransitionCriteria actionChain = TransitionCriteriaChain.criteriaChainFor(actions); + assertFalse(actionChain.test(context)); + } + + private static class TestTransitionCriteria implements TransitionCriteria { + + public boolean tested = false; + private boolean result; + + public TestTransitionCriteria(boolean result) { + this.result = result; + } + + public boolean test(RequestContext context) { + tested = true; + return result; + } + } + + private static class TestAction implements Action { + + private boolean result; + + public TestAction(boolean result) { + this.result = result; + } + + public Event execute(RequestContext context) throws Exception { + if (result) { + return new EventFactorySupport().success(this); + } else { + return new EventFactorySupport().error(this); + } + } + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/execution/factory/StaticFlowExecutionListenerLoaderTests.java b/spring-webflow/src/test/java/org/springframework/webflow/execution/factory/StaticFlowExecutionListenerLoaderTests.java index 25f1e573..5c843631 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/execution/factory/StaticFlowExecutionListenerLoaderTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/execution/factory/StaticFlowExecutionListenerLoaderTests.java @@ -1,54 +1,54 @@ -/* - * 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 - * - * https://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.factory; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; -import org.springframework.webflow.engine.Flow; -import org.springframework.webflow.execution.FlowExecutionListener; - -/** - * Unit tests for {@link StaticFlowExecutionListenerLoader}. - */ -public class StaticFlowExecutionListenerLoaderTests { - - private FlowExecutionListenerLoader loader = StaticFlowExecutionListenerLoader.EMPTY_INSTANCE; - +/* + * 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 + * + * https://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.factory; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.execution.FlowExecutionListener; + +/** + * Unit tests for {@link StaticFlowExecutionListenerLoader}. + */ +public class StaticFlowExecutionListenerLoaderTests { + + private FlowExecutionListenerLoader loader = StaticFlowExecutionListenerLoader.EMPTY_INSTANCE; + @Test - public void testEmptyListenerArray() { - assertEquals(0, loader.getListeners(new Flow("foo")).length); - assertEquals(0, loader.getListeners(null).length); - } - + public void testEmptyListenerArray() { + assertEquals(0, loader.getListeners(new Flow("foo")).length); + assertEquals(0, loader.getListeners(null).length); + } + @Test - public void testStaticListener() { - final FlowExecutionListener listener1 = new FlowExecutionListener() {}; - loader = new StaticFlowExecutionListenerLoader(listener1); - assertEquals(listener1, loader.getListeners(new Flow("foo"))[0]); - } - + public void testStaticListener() { + final FlowExecutionListener listener1 = new FlowExecutionListener() {}; + loader = new StaticFlowExecutionListenerLoader(listener1); + assertEquals(listener1, loader.getListeners(new Flow("foo"))[0]); + } + @Test - public void testStaticListeners() { - final FlowExecutionListener listener1 = new FlowExecutionListener() {}; - final FlowExecutionListener listener2 = new FlowExecutionListener() {}; - - loader = new StaticFlowExecutionListenerLoader(listener1, listener2); - assertEquals(listener1, loader.getListeners(new Flow("foo"))[0]); - assertEquals(listener2, loader.getListeners(new Flow("foo"))[1]); - } - + public void testStaticListeners() { + final FlowExecutionListener listener1 = new FlowExecutionListener() {}; + final FlowExecutionListener listener2 = new FlowExecutionListener() {}; + + loader = new StaticFlowExecutionListenerLoader(listener1, listener2); + assertEquals(listener1, loader.getListeners(new Flow("foo"))[0]); + assertEquals(listener2, loader.getListeners(new Flow("foo"))[1]); + } + } \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/execution/repository/support/CompositeFlowExecutionKeyTests.java b/spring-webflow/src/test/java/org/springframework/webflow/execution/repository/support/CompositeFlowExecutionKeyTests.java index a2c094b3..5242b0bc 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/execution/repository/support/CompositeFlowExecutionKeyTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/execution/repository/support/CompositeFlowExecutionKeyTests.java @@ -1,38 +1,38 @@ -/* - * 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 - * - * https://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.support; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; -import org.springframework.webflow.conversation.impl.SimpleConversationId; - -public class CompositeFlowExecutionKeyTests { - +/* + * 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 + * + * https://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.support; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.springframework.webflow.conversation.impl.SimpleConversationId; + +public class CompositeFlowExecutionKeyTests { + @Test - public void testToString() { - CompositeFlowExecutionKey key = new CompositeFlowExecutionKey(new SimpleConversationId("1"), "1"); - assertEquals("e1s1", key.toString()); - } - + public void testToString() { + CompositeFlowExecutionKey key = new CompositeFlowExecutionKey(new SimpleConversationId("1"), "1"); + assertEquals("e1s1", key.toString()); + } + @Test - public void testEquals() { - CompositeFlowExecutionKey key = new CompositeFlowExecutionKey(new SimpleConversationId("foo"), "bar"); - CompositeFlowExecutionKey key2 = new CompositeFlowExecutionKey(new SimpleConversationId("foo"), "bar"); - assertEquals(key, key2); - } - -} + public void testEquals() { + CompositeFlowExecutionKey key = new CompositeFlowExecutionKey(new SimpleConversationId("foo"), "bar"); + CompositeFlowExecutionKey key2 = new CompositeFlowExecutionKey(new SimpleConversationId("foo"), "bar"); + assertEquals(key, key2); + } + +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java b/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java index 9913d7d3..697bdecc 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/test/SearchFlowExecutionTests.java @@ -1,118 +1,118 @@ -/* - * Copyright 2004-2012 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 - * - * https://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.test; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.jupiter.api.Test; - -import org.springframework.webflow.config.FlowDefinitionResource; -import org.springframework.webflow.config.FlowDefinitionResourceFactory; -import org.springframework.webflow.context.ExternalContext; -import org.springframework.webflow.core.collection.AttributeMap; -import org.springframework.webflow.engine.EndState; -import org.springframework.webflow.engine.Flow; -import org.springframework.webflow.test.execution.AbstractXmlFlowExecutionTests; - -/** - * Sample {@link AbstractXmlFlowExecutionTests} subclass. - */ -public class SearchFlowExecutionTests extends AbstractXmlFlowExecutionTests { - - protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resourceFactory) { - return resourceFactory.createClassPathResource("search-flow.xml", getClass()); - } - - @Test - public void testStartFlow() { - ExternalContext context = new MockExternalContext(); - startFlow(null, context); - assertCurrentStateEquals("enterCriteria"); - } - - @Test - public void testCriteriaSubmitSuccess() { - startFlow(null, new MockExternalContext()); - MockExternalContext context = new MockExternalContext(); - context.putRequestParameter("firstName", "Keith"); - context.putRequestParameter("lastName", "Donald"); - context.setEventId("search"); - resumeFlow(context); - assertCurrentStateEquals("displayResults"); - assertResponseWrittenEquals("searchResults", context); - } - - @Test - public void testNewSearch() { - startFlow(null, new MockExternalContext()); - MockExternalContext context = new MockExternalContext(); - context.putRequestParameter("firstName", "Keith"); - context.putRequestParameter("lastName", "Donald"); - context.setEventId("search"); - resumeFlow(context); - - context = new MockExternalContext(); - context.setEventId("newSearch"); - resumeFlow(context); - assertCurrentStateEquals("enterCriteria"); - assertResponseWrittenEquals("searchCriteria", context); - } - - @Test - public void testSelectValidResult() { - startFlow(null, new MockExternalContext()); - MockExternalContext context = new MockExternalContext(); - context.putRequestParameter("firstName", "Keith"); - context.putRequestParameter("lastName", "Donald"); - context.setEventId("search"); - resumeFlow(context); - - context = new MockExternalContext(); - context.setEventId("select"); - context.putRequestParameter("id", "1"); - resumeFlow(context); - assertCurrentStateEquals("displayResults"); - } - - protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) { - Flow mockDetailFlow = new Flow("detail-flow"); - mockDetailFlow.setInputMapper((source, target) -> { - assertEquals("id of value 1 not provided as input by calling search flow", 1L, ((AttributeMap) source).get("id")); - return null; - }); - // test responding to finish result - new EndState(mockDetailFlow, "finish"); - builderContext.registerSubflow(mockDetailFlow); - builderContext.registerBean("phonebook", new TestPhoneBook()); - } - - public static class TestPhoneBook { - public List search(Object criteria) { - ArrayList res = new ArrayList<>(); - res.add(new Object()); - return res; - } - - public Object getPerson(Long id) { - return new Object(); - } - - public Object getPerson(String userId) { - return new Object(); - } - } -} +/* + * Copyright 2004-2012 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 + * + * https://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.test; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import org.springframework.webflow.config.FlowDefinitionResource; +import org.springframework.webflow.config.FlowDefinitionResourceFactory; +import org.springframework.webflow.context.ExternalContext; +import org.springframework.webflow.core.collection.AttributeMap; +import org.springframework.webflow.engine.EndState; +import org.springframework.webflow.engine.Flow; +import org.springframework.webflow.test.execution.AbstractXmlFlowExecutionTests; + +/** + * Sample {@link AbstractXmlFlowExecutionTests} subclass. + */ +public class SearchFlowExecutionTests extends AbstractXmlFlowExecutionTests { + + protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resourceFactory) { + return resourceFactory.createClassPathResource("search-flow.xml", getClass()); + } + + @Test + public void testStartFlow() { + ExternalContext context = new MockExternalContext(); + startFlow(null, context); + assertCurrentStateEquals("enterCriteria"); + } + + @Test + public void testCriteriaSubmitSuccess() { + startFlow(null, new MockExternalContext()); + MockExternalContext context = new MockExternalContext(); + context.putRequestParameter("firstName", "Keith"); + context.putRequestParameter("lastName", "Donald"); + context.setEventId("search"); + resumeFlow(context); + assertCurrentStateEquals("displayResults"); + assertResponseWrittenEquals("searchResults", context); + } + + @Test + public void testNewSearch() { + startFlow(null, new MockExternalContext()); + MockExternalContext context = new MockExternalContext(); + context.putRequestParameter("firstName", "Keith"); + context.putRequestParameter("lastName", "Donald"); + context.setEventId("search"); + resumeFlow(context); + + context = new MockExternalContext(); + context.setEventId("newSearch"); + resumeFlow(context); + assertCurrentStateEquals("enterCriteria"); + assertResponseWrittenEquals("searchCriteria", context); + } + + @Test + public void testSelectValidResult() { + startFlow(null, new MockExternalContext()); + MockExternalContext context = new MockExternalContext(); + context.putRequestParameter("firstName", "Keith"); + context.putRequestParameter("lastName", "Donald"); + context.setEventId("search"); + resumeFlow(context); + + context = new MockExternalContext(); + context.setEventId("select"); + context.putRequestParameter("id", "1"); + resumeFlow(context); + assertCurrentStateEquals("displayResults"); + } + + protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) { + Flow mockDetailFlow = new Flow("detail-flow"); + mockDetailFlow.setInputMapper((source, target) -> { + assertEquals("id of value 1 not provided as input by calling search flow", 1L, ((AttributeMap) source).get("id")); + return null; + }); + // test responding to finish result + new EndState(mockDetailFlow, "finish"); + builderContext.registerSubflow(mockDetailFlow); + builderContext.registerBean("phonebook", new TestPhoneBook()); + } + + public static class TestPhoneBook { + public List search(Object criteria) { + ArrayList res = new ArrayList<>(); + res.add(new Object()); + return res; + } + + public Object getPerson(Long id) { + return new Object(); + } + + public Object getPerson(String userId) { + return new Object(); + } + } +} diff --git a/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow-beans.xml b/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow-beans.xml index 821fd0ce..d61dd4cc 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow-beans.xml +++ b/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow-beans.xml @@ -1,12 +1,12 @@ - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml b/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml index 5978ece5..e3bbd7c3 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml +++ b/spring-webflow/src/test/java/org/springframework/webflow/test/search-flow.xml @@ -1,30 +1,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file