diff --git a/src/main/java/org/springframework/repeat/CompletionPolicy.java b/src/main/java/org/springframework/repeat/CompletionPolicy.java deleted file mode 100644 index 51fead0..0000000 --- a/src/main/java/org/springframework/repeat/CompletionPolicy.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat; - - -/** - * Interface for batch completion policies, to enable batch operations to - * strategise normal completion conditions. Stateful implementations of batch - * iterators should only update state using the update method. If you - * need custom behaviour consider extending an existing implementation or using - * the composite provided. - * - * @author Dave Syer - * - */ -public interface CompletionPolicy { - - /** - * Determine whether a batch is complete given the latest result from the - * callback. If this method returns true then - * {@link #isComplete(RepeatContext)} should also (but not necessarily vice - * versa, since the answer here depends on the result). - * - * @param context the current batch context. - * @param result the result of the latest batch item processing. - * - * @return true if the batch should terminate. - * - * @see #isComplete(RepeatContext) - */ - boolean isComplete(RepeatContext context, RepeatStatus result); - - /** - * Allow policy to signal completion according to internal state, without - * having to wait for the callback to complete. - * - * @param context the current batch context. - * - * @return true if the batch should terminate. - */ - boolean isComplete(RepeatContext context); - - /** - * Create a new context for the execution of a batch. N.B. implementations - * should not return the parent from this method - they must - * create a new context to meet the specific needs of the policy. The best - * way to do this might be to override an existing implementation and use - * the {@link RepeatContext} to store state in its attributes. - * - * @param parent the current context if one is already in progress. - * @return a context object that can be used by the implementation to store - * internal state for a batch. - */ - RepeatContext start(RepeatContext parent); - - /** - * Give implementations the opportunity to update the state of the current - * batch. Will be called once per callback, after it has been - * launched, but not necessarily after it completes (if the batch is - * asynchronous). - * - * @param context the value returned by start. - */ - void update(RepeatContext context); - -} diff --git a/src/main/java/org/springframework/repeat/RepeatCallback.java b/src/main/java/org/springframework/repeat/RepeatCallback.java deleted file mode 100644 index 2996171..0000000 --- a/src/main/java/org/springframework/repeat/RepeatCallback.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat; - - -/** - * Callback interface for batch operations. Many simple processes will be able - * to use off-the-shelf implementations of this interface, enabling the - * application developer to concentrate on business logic. - * - * @see RepeatOperations - * - * @author Dave Syer - * - */ -public interface RepeatCallback { - - /** - * Implementations return true if they can continue processing - e.g. there - * is a data source that is not yet exhausted. Exceptions are not necessarily - * fatal - processing might continue depending on the Exception type and the - * implementation of the caller. - * - * @param context the current context passed in by the caller. - * @return an {@link RepeatStatus} which is continuable if there is (or may - * be) more data to process. - * @throws Exception if there is a problem with the processing. - */ - RepeatStatus doInIteration(RepeatContext context) throws Exception; -} diff --git a/src/main/java/org/springframework/repeat/RepeatContext.java b/src/main/java/org/springframework/repeat/RepeatContext.java deleted file mode 100644 index bcc528d..0000000 --- a/src/main/java/org/springframework/repeat/RepeatContext.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat; - -import org.springframework.core.AttributeAccessor; - -/** - * Base interface for context which controls the state and completion / - * termination of a batch step. A new context is created for each call to the - * {@link RepeatOperations}. Within a batch callback code can communicate via - * the {@link AttributeAccessor} interface. - * - * @author Dave Syer - * - * @see RepeatOperations#iterate(RepeatCallback) - * - */ -public interface RepeatContext extends AttributeAccessor { - - /** - * If batches are nested, then the inner batch will be created with the - * outer one as a parent. This is an accessor for the parent if it exists. - * - * @return the parent context or null if there is none - */ - RepeatContext getParent(); - - /** - * Public access to a counter for the number of operations attempted. - * - * @return the number of batch operations started. - */ - int getStartedCount(); - - /** - * Signal to the framework that the current batch should complete normally, - * independent of the current {@link CompletionPolicy}. - */ - void setCompleteOnly(); - - /** - * Public accessor for the complete flag. - */ - boolean isCompleteOnly(); - - /** - * Signal to the framework that the current batch should complete - * abnormally, independent of the current {@link CompletionPolicy}. - */ - void setTerminateOnly(); - - /** - * Public accessor for the termination flag. If this flag is set then the - * complete flag will also be. - */ - boolean isTerminateOnly(); - - /** - * Register a callback to be executed on close, associated with the - * attribute having the given name. The {@link Runnable} callback should not - * throw any exceptions. - * - * @param name the name of the attribute to associated this callback with. - * If this attribute is removed the callback should never be called. - * @param callback a {@link Runnable} to execute when the context is closed. - */ - void registerDestructionCallback(String name, Runnable callback); - - /** - * Allow resources to be cleared, especially in destruction callbacks. - * Implementations should ensure that any registered destruction callbacks - * are executed here, as long as the corresponding attribute is still - * available. - */ - void close(); - -} diff --git a/src/main/java/org/springframework/repeat/RepeatException.java b/src/main/java/org/springframework/repeat/RepeatException.java deleted file mode 100644 index 9f02abf..0000000 --- a/src/main/java/org/springframework/repeat/RepeatException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat; - -import org.springframework.core.NestedRuntimeException; - -public class RepeatException extends NestedRuntimeException { - - public RepeatException(String msg) { - super(msg); - } - - public RepeatException(String msg, Throwable t) { - super(msg, t); - } - -} diff --git a/src/main/java/org/springframework/repeat/RepeatListener.java b/src/main/java/org/springframework/repeat/RepeatListener.java deleted file mode 100644 index 834d40b..0000000 --- a/src/main/java/org/springframework/repeat/RepeatListener.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat; - - -/** - * Interface for listeners to the batch process. Implementers can provide - * enhance the behaviour of a batch in small cross-cutting modules. The - * framework provides callbacks at key points in the processing. - * - * @author Dave Syer - * - */ -public interface RepeatListener { - /** - * Called by the framework before each batch item. Implementers can halt a - * batch by setting the complete flag on the context. - * - * @param context the current batch context. - */ - void before(RepeatContext context); - - /** - * Called by the framework after each item has been processed, unless the - * item processing results in an exception. This method is called as soon as - * the result is known. - * - * @param context the current batch context - * @param result the result of the callback - */ - void after(RepeatContext context, RepeatStatus result); - - /** - * Called once at the start of a complete batch, before any items are - * processed. Implementers can use this method to acquire any resources that - * might be needed during processing. Implementers can halt the current - * operation by setting the complete flag on the context. To halt all - * enclosing batches (the whole job), the would need to use the parent - * context (recursively). - * - * @param context the current batch context - */ - void open(RepeatContext context); - - /** - * Called when a repeat callback fails by throwing an exception. There will - * be one call to this method for each exception thrown during a repeat - * operation (e.g. a chunk).
- * - * There is no need to re-throw the exception here - that will be done by - * the enclosing framework. - * - * @param context the current batch context - * @param e the error that was encountered in an item callback. - */ - void onError(RepeatContext context, Throwable e); - - /** - * Called once at the end of a complete batch, after normal or abnormal - * completion (i.e. even after an exception). Implementers can use this - * method to clean up any resources. - * - * @param context the current batch context. - */ - void close(RepeatContext context); -} diff --git a/src/main/java/org/springframework/repeat/RepeatOperations.java b/src/main/java/org/springframework/repeat/RepeatOperations.java deleted file mode 100644 index c6a8965..0000000 --- a/src/main/java/org/springframework/repeat/RepeatOperations.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat; - - -/** - * The main interface providing access to batch operations. The batch client is - * the {@link RepeatCallback}, where a single item or record is processed. The - * batch behaviour, boundary conditions, transactions etc, are dealt with by the - * {@link RepeatOperations} in such as way that the client does not need to know - * about them. The client may have access to framework abstractions, like - * template data sources, but these should work the same whether they are in a - * batch or not. - * - * @author Dave Syer - * - */ -public interface RepeatOperations { - - /** - * Execute the callback repeatedly, until a decision can be made to - * complete. The decision about how many times to execute or when to - * complete, and what to do in the case of an error is delegated to a - * {@link CompletionPolicy}. - * - * @param callback the batch callback. - * @return the aggregate of the result of all the callback operations. An - * indication of whether the {@link RepeatOperations} can continue - * processing if this method is called again. - */ - RepeatStatus iterate(RepeatCallback callback) throws RepeatException; - -} diff --git a/src/main/java/org/springframework/repeat/RepeatStatus.java b/src/main/java/org/springframework/repeat/RepeatStatus.java deleted file mode 100644 index 7b41a51..0000000 --- a/src/main/java/org/springframework/repeat/RepeatStatus.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat; - -public enum RepeatStatus { - - /** - * Indicates that processing can continue. - */ - CONTINUABLE(true), - /** - * Indicates that processing is finished (either successful or unsuccessful) - */ - FINISHED(false); - - private final boolean continuable; - - private RepeatStatus(boolean continuable) { - this.continuable = continuable; - } - - public static RepeatStatus continueIf(boolean continuable) { - return continuable ? CONTINUABLE : FINISHED; - } - - public boolean isContinuable() { - return this == CONTINUABLE; - } - - public RepeatStatus and(boolean value) { - return value && continuable ? CONTINUABLE : FINISHED; - } - -} diff --git a/src/main/java/org/springframework/repeat/callback/NestedRepeatCallback.java b/src/main/java/org/springframework/repeat/callback/NestedRepeatCallback.java deleted file mode 100644 index c5708fe..0000000 --- a/src/main/java/org/springframework/repeat/callback/NestedRepeatCallback.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.callback; - -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatOperations; -import org.springframework.repeat.RepeatStatus; - -/** - * Callback that delegates to another callback, via a {@link RepeatOperations} - * instance. Useful when nesting or composing batches in one another, e.g. for - * breaking a batch down into chunks. - * - * @author Dave Syer - * - */ -public class NestedRepeatCallback implements RepeatCallback { - - private RepeatOperations template; - - private RepeatCallback callback; - - /** - * Constructor setting mandatory fields. - * - * @param template the {@link RepeatOperations} to use when calling the - * delegate callback - * @param callback the {@link RepeatCallback} delegate - */ - public NestedRepeatCallback(RepeatOperations template, RepeatCallback callback) { - super(); - this.template = template; - this.callback = callback; - } - - /** - * Simply calls template.execute(callback). Clients can use this to repeat a - * batch process, or to break a process up into smaller chunks (e.g. to - * change the transaction boundaries). - * - * @see org.springframework.repeat.RepeatCallback#doInIteration(RepeatContext) - */ - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - return template.iterate(callback); - } -} diff --git a/src/main/java/org/springframework/repeat/callback/package.html b/src/main/java/org/springframework/repeat/callback/package.html deleted file mode 100644 index a25a6cf..0000000 --- a/src/main/java/org/springframework/repeat/callback/package.html +++ /dev/null @@ -1,7 +0,0 @@ - - -

-Infrastructure implementations of repeat callback concerns. -

- - diff --git a/src/main/java/org/springframework/repeat/context/RepeatContextCounter.java b/src/main/java/org/springframework/repeat/context/RepeatContextCounter.java deleted file mode 100644 index 9830607..0000000 --- a/src/main/java/org/springframework/repeat/context/RepeatContextCounter.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.context; - -import java.util.concurrent.atomic.AtomicInteger; - -import org.springframework.repeat.RepeatContext; -import org.springframework.util.Assert; - -/** - * Helper class for policies that need to count the number of occurrences of - * some event (e.g. an exception type in the context) in the scope of a batch. - * The value of the counter can be stored between batches in a nested context, - * so that the termination decision is based on the aggregate of a number of - * sibling batches. - * - * @author Dave Syer - * - */ -public class RepeatContextCounter { - - final private String countKey; - - /** - * Flag to indicate whether the count is stored at the level of the parent - * context, or just local to the current context. Default value is false. - */ - final private boolean useParent; - - final private RepeatContext context; - - /** - * Increment the counter. - * - * @param delta the amount by which to increment the counter. - */ - final public void increment(int delta) { - AtomicInteger count = getCounter(); - count.addAndGet(delta); - } - - /** - * Increment by 1. - */ - final public void increment() { - increment(1); - } - - /** - * Convenience constructor with useParent=false. - * @param context the current context. - * @param countKey the key to use to store the counter in the context. - */ - public RepeatContextCounter(RepeatContext context, String countKey) { - this(context, countKey, false); - } - - /** - * Construct a new {@link RepeatContextCounter}. - * - * @param context the current context. - * @param countKey the key to use to store the counter in the context. - * @param useParent true if the counter is to be shared between siblings. - * The state will be stored in the parent of the context (if it exists) - * instead of the context itself. - */ - public RepeatContextCounter(RepeatContext context, String countKey, boolean useParent) { - - super(); - - Assert.notNull(context, "The context must be provided to initialize a counter"); - - this.countKey = countKey; - this.useParent = useParent; - - RepeatContext parent = context.getParent(); - - if (this.useParent && parent != null) { - this.context = parent; - } - else { - this.context = context; - } - if (!this.context.hasAttribute(countKey)) { - this.context.setAttribute(countKey, new AtomicInteger()); - } - - } - - /** - * @return the current value of the counter - */ - public int getCount() { - return getCounter().intValue(); - } - - private AtomicInteger getCounter() { - return ((AtomicInteger) context.getAttribute(countKey)); - } - -} diff --git a/src/main/java/org/springframework/repeat/context/RepeatContextSupport.java b/src/main/java/org/springframework/repeat/context/RepeatContextSupport.java deleted file mode 100644 index 8430b7a..0000000 --- a/src/main/java/org/springframework/repeat/context/RepeatContextSupport.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.context; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.springframework.repeat.RepeatContext; - -public class RepeatContextSupport extends SynchronizedAttributeAccessor implements RepeatContext { - - private RepeatContext parent; - - private int count; - - private volatile boolean completeOnly; - - private volatile boolean terminateOnly; - - private Map> callbacks = new HashMap>(); - - /** - * Constructor for {@link RepeatContextSupport}. The parent can be null, but - * should be set to the enclosing repeat context if there is one, e.g. if - * this context is an inner loop. - * @param parent - */ - public RepeatContextSupport(RepeatContext parent) { - super(); - this.parent = parent; - } - - /* - * (non-Javadoc) - * - * @see org.springframework.batch.repeat.RepeatContext#isCompleteOnly() - */ - public boolean isCompleteOnly() { - return completeOnly; - } - - /* - * (non-Javadoc) - * - * @see org.springframework.batch.repeat.RepeatContext#setCompleteOnly() - */ - public void setCompleteOnly() { - completeOnly = true; - } - - /* - * (non-Javadoc) - * - * @see org.springframework.batch.repeat.RepeatContext#isTerminateOnly() - */ - public boolean isTerminateOnly() { - return terminateOnly; - } - - /* - * (non-Javadoc) - * - * @see org.springframework.batch.repeat.RepeatContext#setTerminateOnly() - */ - public void setTerminateOnly() { - terminateOnly = true; - setCompleteOnly(); - } - - /* - * (non-Javadoc) - * - * @see org.springframework.batch.repeat.RepeatContext#getParent() - */ - public RepeatContext getParent() { - return parent; - } - - /** - * Used by clients to increment the started count. - */ - public synchronized void increment() { - count++; - } - - /* - * (non-Javadoc) - * - * @see org.springframework.batch.repeat.RepeatContext#getStartedCount() - */ - public synchronized int getStartedCount() { - return count; - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.batch.repeat.RepeatContext#registerDestructionCallback - * (java.lang.String, java.lang.Runnable) - */ - public void registerDestructionCallback(String name, Runnable callback) { - synchronized (callbacks) { - Set set = callbacks.get(name); - if (set == null) { - set = new HashSet(); - callbacks.put(name, set); - } - set.add(callback); - } - } - - /* - * (non-Javadoc) - * - * @see org.springframework.batch.repeat.RepeatContext#close() - */ - public void close() { - - List errors = new ArrayList(); - - Set>> copy; - - synchronized (callbacks) { - copy = new HashSet>>(callbacks.entrySet()); - } - - for (Map.Entry> entry : copy) { - - for (Runnable callback : entry.getValue()) { - /* - * Potentially we could check here if there is an attribute with - * the given name - if it has been removed, maybe the callback - * is invalid. On the other hand it is less surprising for the - * callback register if it is always executed. - */ - if (callback != null) { - /* - * The documentation of the interface says that these - * callbacks must not throw exceptions, but we don't trust - * them necessarily... - */ - try { - callback.run(); - } - catch (RuntimeException t) { - errors.add(t); - } - } - } - } - - if (errors.isEmpty()) { - return; - } - - throw (RuntimeException) errors.get(0); - } - -} diff --git a/src/main/java/org/springframework/repeat/context/SynchronizedAttributeAccessor.java b/src/main/java/org/springframework/repeat/context/SynchronizedAttributeAccessor.java deleted file mode 100644 index f67b2b6..0000000 --- a/src/main/java/org/springframework/repeat/context/SynchronizedAttributeAccessor.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.context; - -import org.springframework.core.AttributeAccessor; -import org.springframework.core.AttributeAccessorSupport; - -/** - * An {@link AttributeAccessor} that synchronizes on a mutex (not this) before - * modifying or accessing the underlying attributes. - * - * @author Dave Syer - * - */ -public class SynchronizedAttributeAccessor implements AttributeAccessor { - - /** - * All methods are delegated to this support object. - */ - AttributeAccessorSupport support = new AttributeAccessorSupport() { - /** - * Generated serial UID. - */ - private static final long serialVersionUID = -7664290016506582290L; - }; - - /* - * (non-Javadoc) - * @see org.springframework.core.AttributeAccessor#attributeNames() - */ - public String[] attributeNames() { - synchronized (support) { - return support.attributeNames(); - } - } - - /* - * (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object other) { - if (this == other) { - return true; - } - AttributeAccessorSupport that; - if (other instanceof SynchronizedAttributeAccessor) { - that = ((SynchronizedAttributeAccessor) other).support; - } - else if (other instanceof AttributeAccessorSupport) { - that = (AttributeAccessorSupport) other; - } - else { - return false; - } - synchronized (support) { - return support.equals(that); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.core.AttributeAccessor#getAttribute(java.lang.String) - */ - public Object getAttribute(String name) { - synchronized (support) { - return support.getAttribute(name); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.core.AttributeAccessor#hasAttribute(java.lang.String) - */ - public boolean hasAttribute(String name) { - synchronized (support) { - return support.hasAttribute(name); - } - } - - /* - * (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - public int hashCode() { - return support.hashCode(); - } - - /* - * (non-Javadoc) - * @see org.springframework.core.AttributeAccessor#removeAttribute(java.lang.String) - */ - public Object removeAttribute(String name) { - synchronized (support) { - return support.removeAttribute(name); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.core.AttributeAccessor#setAttribute(java.lang.String, - * java.lang.Object) - */ - public void setAttribute(String name, Object value) { - synchronized (support) { - support.setAttribute(name, value); - } - } - - /** - * Additional support for atomic put if absent. - * @param name the key for the attribute name - * @param value the value of the attribute - * @return null if the attribute was not already set, the existing value - * otherwise. - */ - public Object setAttributeIfAbsent(String name, Object value) { - synchronized (support) { - Object old = getAttribute(name); - if (old != null) { - return old; - } - setAttribute(name, value); - } - return null; - } - - /* - * (non-Javadoc) - * @see java.lang.Object#toString() - */ - public String toString() { - StringBuffer buffer = new StringBuffer("SynchronizedAttributeAccessor: ["); - synchronized (support) { - String[] names = attributeNames(); - for (int i = 0; i < names.length; i++) { - String name = names[i]; - buffer.append(names[i]).append("=").append(getAttribute(name)); - if (i < names.length - 1) { - buffer.append(", "); - } - } - buffer.append("]"); - return buffer.toString(); - } - } - -} diff --git a/src/main/java/org/springframework/repeat/context/package.html b/src/main/java/org/springframework/repeat/context/package.html deleted file mode 100644 index 7bb43fa..0000000 --- a/src/main/java/org/springframework/repeat/context/package.html +++ /dev/null @@ -1,7 +0,0 @@ - - -

-Infrastructure implementations of repeat context concerns. -

- - diff --git a/src/main/java/org/springframework/repeat/exception/CompositeExceptionHandler.java b/src/main/java/org/springframework/repeat/exception/CompositeExceptionHandler.java deleted file mode 100644 index ba808ef..0000000 --- a/src/main/java/org/springframework/repeat/exception/CompositeExceptionHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import java.util.Arrays; - -import org.springframework.repeat.RepeatContext; - -/** - * Composiste {@link ExceptionHandler} that loops though a list of delegates. - * - * @author Dave Syer - * - */ -public class CompositeExceptionHandler implements ExceptionHandler { - - private ExceptionHandler[] handlers = new ExceptionHandler[0]; - - public void setHandlers(ExceptionHandler[] handlers) { - this.handlers = Arrays.asList(handlers).toArray(new ExceptionHandler[handlers.length]); - } - - /** - * Iterate over the handlers delegating the call to each in turn. The chain - * ends if an exception is thrown. - * - * @see ExceptionHandler#handleException(RepeatContext, Throwable) - */ - public void handleException(RepeatContext context, Throwable throwable) throws Throwable { - for (int i = 0; i < handlers.length; i++) { - ExceptionHandler handler = handlers[i]; - handler.handleException(context, throwable); - } - } -} diff --git a/src/main/java/org/springframework/repeat/exception/DefaultExceptionHandler.java b/src/main/java/org/springframework/repeat/exception/DefaultExceptionHandler.java deleted file mode 100644 index eb1ce51..0000000 --- a/src/main/java/org/springframework/repeat/exception/DefaultExceptionHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import org.springframework.repeat.RepeatContext; - -/** - * Default implementation of {@link ExceptionHandler} - just re-throws the exception it encounters. - * - * @author Dave Syer - * - */ -public class DefaultExceptionHandler implements ExceptionHandler { - - /** - * Re-throw the throwable. - * - * @see org.springframework.repeat.exception.ExceptionHandler#handleException(RepeatContext, - * Throwable) - */ - public void handleException(RepeatContext context, Throwable throwable) throws Throwable { - throw throwable; - } - -} diff --git a/src/main/java/org/springframework/repeat/exception/ExceptionHandler.java b/src/main/java/org/springframework/repeat/exception/ExceptionHandler.java deleted file mode 100644 index 0634952..0000000 --- a/src/main/java/org/springframework/repeat/exception/ExceptionHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import org.springframework.repeat.CompletionPolicy; -import org.springframework.repeat.RepeatContext; - -/** - * Handler to allow strategies for re-throwing exceptions. Normally a - * {@link CompletionPolicy} will be used to decide whether to end a batch when - * there is no exception, and the {@link ExceptionHandler} is used to signal an - * abnormal ending - an abnormal ending would result in an - * {@link ExceptionHandler} throwing an exception. The caller will catch and - * re-throw it if necessary. - * - * @author Dave Syer - * @author Robert Kasanicky - * - */ -public interface ExceptionHandler { - - /** - * Deal with a Throwable during a batch - decide whether it should be - * re-thrown in the first place. - * - * @param context the current {@link RepeatContext}. Can be used to store - * state (via attributes), for example to count the number of occurrences of - * a particular exception type and implement a threshold policy. - * @param throwable an exception. - * @throws Throwable implementations are free to re-throw the exception - */ - void handleException(RepeatContext context, Throwable throwable) throws Throwable; - -} diff --git a/src/main/java/org/springframework/repeat/exception/LogOrRethrowExceptionHandler.java b/src/main/java/org/springframework/repeat/exception/LogOrRethrowExceptionHandler.java deleted file mode 100644 index 51f03d1..0000000 --- a/src/main/java/org/springframework/repeat/exception/LogOrRethrowExceptionHandler.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.classify.Classifier; -import org.springframework.classify.ClassifierSupport; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatException; - -/** - * Implementation of {@link ExceptionHandler} based on an {@link Classifier}. - * The classifier determines whether to log the exception or rethrow it. The - * keys in the classifier must be the same as the static enum in this class. - * - * @author Dave Syer - * - */ -public class LogOrRethrowExceptionHandler implements ExceptionHandler { - - /** - * Logging levels for the handler. - * - * @author Dave Syer - * - */ - public static enum Level { - - /** - * Key for {@link Classifier} signalling that the throwable should be - * rethrown. If the throwable is not a RuntimeException it is wrapped in - * a {@link RepeatException}. - */ - RETHROW, - - /** - * Key for {@link Classifier} signalling that the throwable should be - * logged at debug level. - */ - DEBUG, - - /** - * Key for {@link Classifier} signalling that the throwable should be - * logged at warn level. - */ - WARN, - - /** - * Key for {@link Classifier} signalling that the throwable should be - * logged at error level. - */ - ERROR - - } - - protected final Log logger = LogFactory.getLog(LogOrRethrowExceptionHandler.class); - - private Classifier exceptionClassifier = new ClassifierSupport(Level.RETHROW); - - /** - * Setter for the {@link Classifier} used by this handler. The default is to - * map all throwable instances to {@link Level#RETHROW}. - * - * @param exceptionClassifier the ExceptionClassifier to use - */ - public void setExceptionClassifier(Classifier exceptionClassifier) { - this.exceptionClassifier = exceptionClassifier; - } - - /** - * Classify the throwables and decide whether to rethrow based on the - * result. The context is not used. - * - * @throws Throwable - * - * @see ExceptionHandler#handleException(RepeatContext, Throwable) - */ - public void handleException(RepeatContext context, Throwable throwable) throws Throwable { - - Level key = exceptionClassifier.classify(throwable); - if (Level.ERROR.equals(key)) { - logger.error("Exception encountered in batch repeat.", throwable); - } - else if (Level.WARN.equals(key)) { - logger.warn("Exception encountered in batch repeat.", throwable); - } - else if (Level.DEBUG.equals(key) && logger.isDebugEnabled()) { - logger.debug("Exception encountered in batch repeat.", throwable); - } - else if (Level.RETHROW.equals(key)) { - throw throwable; - } - - } - -} diff --git a/src/main/java/org/springframework/repeat/exception/RethrowOnThresholdExceptionHandler.java b/src/main/java/org/springframework/repeat/exception/RethrowOnThresholdExceptionHandler.java deleted file mode 100644 index 22b61a9..0000000 --- a/src/main/java/org/springframework/repeat/exception/RethrowOnThresholdExceptionHandler.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.classify.Classifier; -import org.springframework.classify.SubclassClassifier; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.context.RepeatContextCounter; -import org.springframework.util.ObjectUtils; - -/** - * Implementation of {@link ExceptionHandler} that rethrows when exceptions of a - * given type reach a threshold. Requires an {@link Classifier} that maps - * exception types to unique keys, and also a map from those keys to threshold - * values (Integer type). - * - * @author Dave Syer - * - */ -public class RethrowOnThresholdExceptionHandler implements ExceptionHandler { - - protected static final IntegerHolder ZERO = new IntegerHolder(0); - - protected final Log logger = LogFactory.getLog(RethrowOnThresholdExceptionHandler.class); - - private Classifier exceptionClassifier = new Classifier() { - public RethrowOnThresholdExceptionHandler.IntegerHolder classify(Throwable classifiable) { - return ZERO; - } - }; - - private boolean useParent = false; - - /** - * Flag to indicate the the exception counters should be shared between - * sibling contexts in a nested batch. Default is false. - * - * @param useParent true if the parent context should be used to store the - * counters. - */ - public void setUseParent(boolean useParent) { - this.useParent = useParent; - } - - /** - * Set up the exception handler. Creates a default exception handler and - * threshold that maps all exceptions to a threshold of 0 - all exceptions - * are rethrown by default. - */ - public RethrowOnThresholdExceptionHandler() { - super(); - } - - /** - * A map from exception classes to a threshold value of type Integer. - * - * @param thresholds the threshold value map. - */ - public void setThresholds(Map, Integer> thresholds) { - Map, IntegerHolder> typeMap = new HashMap, IntegerHolder>(); - for (Entry, Integer> entry : thresholds.entrySet()) { - typeMap.put(entry.getKey(), new IntegerHolder(entry.getValue())); - } - exceptionClassifier = new SubclassClassifier(typeMap, ZERO); - } - - /** - * Classify the throwables and decide whether to re-throw based on the - * result. The context is used to accumulate the number of exceptions of the - * same type according to the classifier. - * - * @throws Throwable - * @see ExceptionHandler#handleException(RepeatContext, Throwable) - */ - public void handleException(RepeatContext context, Throwable throwable) throws Throwable { - - IntegerHolder key = exceptionClassifier.classify(throwable); - - RepeatContextCounter counter = getCounter(context, key); - counter.increment(); - int count = counter.getCount(); - int threshold = key.getValue(); - if (count > threshold) { - throw throwable; - } - - } - - private RepeatContextCounter getCounter(RepeatContext context, IntegerHolder key) { - String attribute = RethrowOnThresholdExceptionHandler.class.getName() + "." + key; - // Creates a new counter and stores it in the correct context: - return new RepeatContextCounter(context, attribute, useParent); - } - - /** - * @author Dave Syer - * - */ - private static class IntegerHolder { - - private final int value; - - /** - * @param value - */ - public IntegerHolder(int value) { - this.value = value; - } - - /** - * Public getter for the value. - * @return the value - */ - public int getValue() { - return value; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return ObjectUtils.getIdentityHexString(this) + "." + value; - } - - } - -} diff --git a/src/main/java/org/springframework/repeat/exception/SimpleLimitExceptionHandler.java b/src/main/java/org/springframework/repeat/exception/SimpleLimitExceptionHandler.java deleted file mode 100644 index 1786091..0000000 --- a/src/main/java/org/springframework/repeat/exception/SimpleLimitExceptionHandler.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.repeat.RepeatContext; - -/** - * Simple implementation of exception handler which looks for given exception - * types. If one of the types is found then a counter is incremented and the - * limit is checked to determine if it has been exceeded and the Throwable - * should be re-thrown. Also allows to specify list of 'fatal' exceptions that - * are never subject to counting, but are immediately re-thrown. The fatal list - * has higher priority so the two lists needn't be exclusive. - * - * @author Dave Syer - * @author Robert Kasanicky - */ -public class SimpleLimitExceptionHandler implements ExceptionHandler, InitializingBean { - - private RethrowOnThresholdExceptionHandler delegate = new RethrowOnThresholdExceptionHandler(); - - private Collection> exceptionClasses = Collections - .> singleton(Exception.class); - - private Collection> fatalExceptionClasses = Collections - .> singleton(Error.class); - - private int limit = 0; - - /** - * Apply the provided properties to create a delegate handler. - * - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - */ - public void afterPropertiesSet() throws Exception { - if (limit <= 0) { - return; - } - Map, Integer> thresholds = new HashMap, Integer>(); - for (Class type : exceptionClasses) { - thresholds.put(type, limit); - } - // do the fatalExceptionClasses last so they override the others - for (Class type : fatalExceptionClasses) { - thresholds.put(type, 0); - } - delegate.setThresholds(thresholds); - } - - /** - * Flag to indicate the the exception counters should be shared between - * sibling contexts in a nested batch (i.e. inner loop). Default is false. - * Set this flag to true if you want to count exceptions for the whole - * (outer) loop in a typical container. - * - * @param useParent true if the parent context should be used to store the - * counters. - */ - public void setUseParent(boolean useParent) { - delegate.setUseParent(useParent); - } - - /** - * Convenience constructor for the {@link SimpleLimitExceptionHandler} to - * set the limit. - * - * @param limit the limit - */ - public SimpleLimitExceptionHandler(int limit) { - this(); - this.limit = limit; - } - - /** - * Default constructor for the {@link SimpleLimitExceptionHandler}. - */ - public SimpleLimitExceptionHandler() { - super(); - } - - /** - * Rethrows only if the limit is breached for this context on the exception - * type specified. - * - * @see #setExceptionClasses(Collection) - * @see #setLimit(int) - * - * @see org.springframework.repeat.exception.ExceptionHandler#handleException(org.springframework.repeat.RepeatContext, - * Throwable) - */ - public void handleException(RepeatContext context, Throwable throwable) throws Throwable { - delegate.handleException(context, throwable); - } - - /** - * The limit on the given exception type within a single context before it - * is rethrown. - * - * @param limit the limit - */ - public void setLimit(final int limit) { - this.limit = limit; - } - - /** - * Setter for the exception classes that this handler counts. Defaults to - * {@link Exception}. If more exceptionClasses are specified handler uses - * single counter that is incremented when one of the recognized exception - * exceptionClasses is handled. - * @param classes exceptionClasses - */ - public void setExceptionClasses(Collection> classes) { - this.exceptionClasses = classes; - } - - /** - * Setter for the exception classes that shouldn't be counted, but rethrown - * immediately. This list has higher priority than - * {@link #setExceptionClasses(Collection)}. - * - * @param fatalExceptionClasses defaults to {@link Error} - */ - public void setFatalExceptionClasses(Collection> fatalExceptionClasses) { - this.fatalExceptionClasses = fatalExceptionClasses; - } - -} diff --git a/src/main/java/org/springframework/repeat/exception/package.html b/src/main/java/org/springframework/repeat/exception/package.html deleted file mode 100644 index edbc051..0000000 --- a/src/main/java/org/springframework/repeat/exception/package.html +++ /dev/null @@ -1,7 +0,0 @@ - - -

-Infrastructure implementations of repeat exception handler concerns. -

- - diff --git a/src/main/java/org/springframework/repeat/interceptor/RepeatOperationsInterceptor.java b/src/main/java/org/springframework/repeat/interceptor/RepeatOperationsInterceptor.java deleted file mode 100644 index 37c5c3b..0000000 --- a/src/main/java/org/springframework/repeat/interceptor/RepeatOperationsInterceptor.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.interceptor; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.springframework.aop.ProxyMethodInvocation; -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatException; -import org.springframework.repeat.RepeatOperations; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.support.RepeatTemplate; -import org.springframework.util.Assert; - -/** - * A {@link MethodInterceptor} that can be used to automatically repeat calls to - * a method on a service. The injected {@link RepeatOperations} is used to - * control the completion of the loop. Independent of the completion policy in - * the {@link RepeatOperations} the loop will repeat until the target method - * returns null or false. Be careful when injecting a bespoke - * {@link RepeatOperations} that the loop will actually terminate, because the - * default policy for a vanilla {@link RepeatTemplate} will never complete if - * the return type of the target method is void (the value returned is always - * not-null, representing the {@link Void#TYPE}). - * - * @author Dave Syer - */ -public class RepeatOperationsInterceptor implements MethodInterceptor { - - private RepeatOperations repeatOperations = new RepeatTemplate(); - - /** - * Setter for the {@link RepeatOperations}. - * - * @param batchTempate - * @throws IllegalArgumentException if the argument is null. - */ - public void setRepeatOperations(RepeatOperations batchTempate) { - Assert.notNull(batchTempate, "'repeatOperations' cannot be null."); - this.repeatOperations = batchTempate; - } - - /** - * Invoke the proceeding method call repeatedly, according to the properties - * of the injected {@link RepeatOperations}. - * - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) - */ - public Object invoke(final MethodInvocation invocation) throws Throwable { - - final ResultHolder result = new ResultHolder(); - // Cache void return value if intercepted method returns void - final boolean voidReturnType = Void.TYPE.equals(invocation.getMethod().getReturnType()); - if (voidReturnType) { - // This will be ignored anyway, but we want it to be non-null for - // convenience of checking that there is a result. - result.setValue(new Object()); - } - - try { - repeatOperations.iterate(new RepeatCallback() { - - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - try { - - MethodInvocation clone = invocation; - if (invocation instanceof ProxyMethodInvocation) { - clone = ((ProxyMethodInvocation) invocation).invocableClone(); - } - else { - throw new IllegalStateException( - "MethodInvocation of the wrong type detected - this should not happen with Spring AOP, so please raise an issue if you see this exception"); - } - - Object value = clone.proceed(); - if (voidReturnType) { - return RepeatStatus.CONTINUABLE; - } - if (!isComplete(value)) { - // Save the last result - result.setValue(value); - return RepeatStatus.CONTINUABLE; - } - else { - result.setFinalValue(value); - return RepeatStatus.FINISHED; - } - } - catch (Throwable e) { - if (e instanceof Exception) { - throw (Exception) e; - } - else { - throw new RepeatOperationsInterceptorException("Unexpected error in batch interceptor", e); - } - } - } - - }); - } - catch (Throwable t) { - // The repeat exception should be unwrapped by the template - throw t; - } - - if (result.isReady()) { - return result.getValue(); - } - - // No result means something weird happened - throw new IllegalStateException("No result available for attempted repeat call to " + invocation - + ". The invocation was never called, so maybe there is a problem with the completion policy?"); - } - - /** - * @param result - * @return - */ - private boolean isComplete(Object result) { - return result == null || (result instanceof Boolean) && !((Boolean) result).booleanValue(); - } - - /** - * Simple wrapper exception class to enable nasty errors to be passed out of - * the scope of the repeat operations and handled by the caller. - * - * @author Dave Syer - * - */ - private static class RepeatOperationsInterceptorException extends RepeatException { - /** - * @param message - * @param e - */ - public RepeatOperationsInterceptorException(String message, Throwable e) { - super(message, e); - } - } - - /** - * Simple wrapper object for the result from a method invocation. - * - * @author Dave Syer - * - */ - private static class ResultHolder { - private Object value = null; - - private boolean ready = false; - - /** - * Public setter for the Object. - * @param value the value to set - */ - public void setValue(Object value) { - this.ready = true; - this.value = value; - } - - /** - * @param value - */ - public void setFinalValue(Object value) { - if (ready) { - // Only set the value the last time if the last time was also - // the first time - return; - } - setValue(value); - } - - /** - * Public getter for the Object. - * @return the value - */ - public Object getValue() { - return value; - } - - /** - * @return true if a value has been set - */ - public boolean isReady() { - return ready; - } - } - -} diff --git a/src/main/java/org/springframework/repeat/interceptor/package.html b/src/main/java/org/springframework/repeat/interceptor/package.html deleted file mode 100644 index bb348ce..0000000 --- a/src/main/java/org/springframework/repeat/interceptor/package.html +++ /dev/null @@ -1,7 +0,0 @@ - - -

-Infrastructure implementations of repeat aop concerns. -

- - diff --git a/src/main/java/org/springframework/repeat/listener/CompositeRepeatListener.java b/src/main/java/org/springframework/repeat/listener/CompositeRepeatListener.java deleted file mode 100644 index 57c3204..0000000 --- a/src/main/java/org/springframework/repeat/listener/CompositeRepeatListener.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.repeat.listener; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatListener; -import org.springframework.repeat.RepeatStatus; - -/** - * @author Dave Syer - * - */ -public class CompositeRepeatListener implements RepeatListener { - - private List listeners = new ArrayList(); - - /** - * Public setter for the listeners. - * - * @param listeners - */ - public void setListeners(RepeatListener[] listeners) { - this.listeners = Arrays.asList(listeners); - } - - /** - * Register additional listener. - * - * @param listener - */ - public void register(RepeatListener listener) { - if (!listeners.contains(listener)) { - listeners.add(listener); - } - } - - /* (non-Javadoc) - * @see org.springframework.batch.repeat.RepeatListener#after(org.springframework.batch.repeat.RepeatContext, org.springframework.batch.repeat.ExitStatus) - */ - public void after(RepeatContext context, RepeatStatus result) { - for (RepeatListener listener : listeners) { - listener.after(context, result); - } - } - - /* (non-Javadoc) - * @see org.springframework.batch.repeat.RepeatListener#before(org.springframework.batch.repeat.RepeatContext) - */ - public void before(RepeatContext context) { - for (RepeatListener listener : listeners) { - listener.before(context); - } - } - - /* (non-Javadoc) - * @see org.springframework.batch.repeat.RepeatListener#close(org.springframework.batch.repeat.RepeatContext) - */ - public void close(RepeatContext context) { - for (RepeatListener listener : listeners) { - listener.close(context); - } - } - - /* (non-Javadoc) - * @see org.springframework.batch.repeat.RepeatListener#onError(org.springframework.batch.repeat.RepeatContext, java.lang.Throwable) - */ - public void onError(RepeatContext context, Throwable e) { - for (RepeatListener listener : listeners) { - listener.onError(context, e); - } - } - - /* (non-Javadoc) - * @see org.springframework.batch.repeat.RepeatListener#open(org.springframework.batch.repeat.RepeatContext) - */ - public void open(RepeatContext context) { - for (RepeatListener listener : listeners) { - listener.open(context); - } - } - -} diff --git a/src/main/java/org/springframework/repeat/listener/RepeatListenerSupport.java b/src/main/java/org/springframework/repeat/listener/RepeatListenerSupport.java deleted file mode 100644 index 8335adb..0000000 --- a/src/main/java/org/springframework/repeat/listener/RepeatListenerSupport.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.listener; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatListener; -import org.springframework.repeat.RepeatStatus; - -/** - * Empty method implementation of {@link RepeatListener}. - * - * @author Dave Syer - * - */ -public class RepeatListenerSupport implements RepeatListener { - - public void before(RepeatContext context) { - } - - public void after(RepeatContext context, RepeatStatus result) { - } - - public void close(RepeatContext context) { - } - - public void onError(RepeatContext context, Throwable e) { - } - - public void open(RepeatContext context) { - } - -} diff --git a/src/main/java/org/springframework/repeat/listener/package.html b/src/main/java/org/springframework/repeat/listener/package.html deleted file mode 100644 index 8a95d83..0000000 --- a/src/main/java/org/springframework/repeat/listener/package.html +++ /dev/null @@ -1,7 +0,0 @@ - - -

-Infrastructure implementations of repeat interceptor concerns. -

- - diff --git a/src/main/java/org/springframework/repeat/package.html b/src/main/java/org/springframework/repeat/package.html deleted file mode 100644 index 531b1f8..0000000 --- a/src/main/java/org/springframework/repeat/package.html +++ /dev/null @@ -1,7 +0,0 @@ - - -

-Infrastructure implementations of repeat concerns. -

- - diff --git a/src/main/java/org/springframework/repeat/policy/CompletionPolicySupport.java b/src/main/java/org/springframework/repeat/policy/CompletionPolicySupport.java deleted file mode 100644 index 952dfe9..0000000 --- a/src/main/java/org/springframework/repeat/policy/CompletionPolicySupport.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import org.springframework.repeat.CompletionPolicy; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.context.RepeatContextSupport; - -/** - * Very simple base class for {@link CompletionPolicy} implementations. - * - * @author Dave Syer - * - */ -public class CompletionPolicySupport implements CompletionPolicy { - - /** - * If exit status is not continuable return true, otherwise - * delegate to {@link #isComplete(RepeatContext)}. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(org.springframework.repeat.RepeatContext, - * RepeatStatus) - */ - public boolean isComplete(RepeatContext context, RepeatStatus result) { - if (result != null && !result.isContinuable()) { - return true; - } - else { - return isComplete(context); - } - } - - /** - * Always true. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(org.springframework.repeat.RepeatContext) - */ - public boolean isComplete(RepeatContext context) { - return true; - } - - /** - * Build a new {@link RepeatContextSupport} and return it. - * - * @see org.springframework.repeat.CompletionPolicy#start(RepeatContext) - */ - public RepeatContext start(RepeatContext context) { - return new RepeatContextSupport(context); - } - - /** - * Increment the context so the counter is up to date. Do nothing else. - * - * @see org.springframework.repeat.CompletionPolicy#update(org.springframework.repeat.RepeatContext) - */ - public void update(RepeatContext context) { - if (context instanceof RepeatContextSupport) { - ((RepeatContextSupport) context).increment(); - } - } - -} diff --git a/src/main/java/org/springframework/repeat/policy/CompositeCompletionPolicy.java b/src/main/java/org/springframework/repeat/policy/CompositeCompletionPolicy.java deleted file mode 100644 index 589c6ae..0000000 --- a/src/main/java/org/springframework/repeat/policy/CompositeCompletionPolicy.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.springframework.repeat.CompletionPolicy; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.context.RepeatContextSupport; - -/** - * Composite policy that loops through a list of delegate policies and answers - * calls by a concensus. - * - * @author Dave Syer - * - */ -public class CompositeCompletionPolicy implements CompletionPolicy { - - CompletionPolicy[] policies = new CompletionPolicy[0]; - - /** - * Setter for the policies. - * - * @param policies - */ - public void setPolicies(CompletionPolicy[] policies) { - this.policies = Arrays.asList(policies).toArray(new CompletionPolicy[policies.length]); - } - - /** - * This policy is complete if any of the composed policies is complete. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(org.springframework.repeat.RepeatContext, - * RepeatStatus) - */ - public boolean isComplete(RepeatContext context, RepeatStatus result) { - RepeatContext[] contexts = ((CompositeBatchContext) context).contexts; - CompletionPolicy[] policies = ((CompositeBatchContext) context).policies; - for (int i = 0; i < policies.length; i++) { - if (policies[i].isComplete(contexts[i], result)) { - return true; - } - } - return false; - } - - /** - * This policy is complete if any of the composed policies is complete. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(org.springframework.repeat.RepeatContext) - */ - public boolean isComplete(RepeatContext context) { - RepeatContext[] contexts = ((CompositeBatchContext) context).contexts; - CompletionPolicy[] policies = ((CompositeBatchContext) context).policies; - for (int i = 0; i < policies.length; i++) { - if (policies[i].isComplete(contexts[i])) { - return true; - } - } - return false; - } - - /** - * Create a new composite context from all the available policies. - * - * @see org.springframework.repeat.CompletionPolicy#start(RepeatContext) - */ - public RepeatContext start(RepeatContext context) { - List list = new ArrayList(); - for (int i = 0; i < policies.length; i++) { - list.add(policies[i].start(context)); - } - return new CompositeBatchContext(context, list); - - } - - /** - * Update all the composed contexts, and also increment the parent context. - * - * @see org.springframework.repeat.CompletionPolicy#update(org.springframework.repeat.RepeatContext) - */ - public void update(RepeatContext context) { - RepeatContext[] contexts = ((CompositeBatchContext) context).contexts; - CompletionPolicy[] policies = ((CompositeBatchContext) context).policies; - for (int i = 0; i < policies.length; i++) { - policies[i].update(contexts[i]); - } - ((RepeatContextSupport) context).increment(); - } - - /** - * Composite context that knows about the policies and contexts is was - * created with. - * - * @author Dave Syer - * - */ - protected class CompositeBatchContext extends RepeatContextSupport { - - private RepeatContext[] contexts; - - // Save a reference to the policies when we were created - gives some - // protection against reference changes (e.g. if the number of policies - // change). - private CompletionPolicy[] policies; - - public CompositeBatchContext(RepeatContext context, List contexts) { - super(context); - this.contexts = contexts.toArray(new RepeatContext[contexts.size()]); - this.policies = CompositeCompletionPolicy.this.policies; - } - - } - -} diff --git a/src/main/java/org/springframework/repeat/policy/CountingCompletionPolicy.java b/src/main/java/org/springframework/repeat/policy/CountingCompletionPolicy.java deleted file mode 100644 index 528a6c3..0000000 --- a/src/main/java/org/springframework/repeat/policy/CountingCompletionPolicy.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.context.RepeatContextCounter; -import org.springframework.repeat.context.RepeatContextSupport; - -/** - * Abstract base class for policies that need to count the number of occurrences - * of some event (e.g. an exception type in the context), and terminate based on - * a limit for the counter. The value of the counter can be stored between - * batches in a nested context, so that the termination decision is based on the - * aggregate of a number of sibling batches. - * - * @author Dave Syer - * - */ -public abstract class CountingCompletionPolicy extends DefaultResultCompletionPolicy { - - /** - * Session key for global counter. - */ - public static final String COUNT = CountingCompletionPolicy.class.getName() + ".COUNT"; - - private boolean useParent = false; - - private int maxCount = 0; - - /** - * Flag to indicate whether the count is at the level of the parent context, - * or just local to the context. If true then the count is aggregated among - * siblings in a nested batch. - * - * @param useParent whether to use the parent context to cache the total - * count. Default value is false. - */ - public void setUseParent(boolean useParent) { - this.useParent = useParent; - } - - /** - * Setter for maximum value of count before termination. - * - * @param maxCount the maximum number of counts before termination. Default - * 0 so termination is immediate. - */ - public void setMaxCount(int maxCount) { - this.maxCount = maxCount; - } - - /** - * Extension point for subclasses. Obtain the value of the count in the - * current context. Subclasses can count the number of attempts or - * violations and store the result in their context. This policy base class - * will take care of the termination contract and aggregating at the level - * of the session if required. - * - * @param context the current context, specific to the subclass. - * @return the value of the counter in the context. - */ - protected abstract int getCount(RepeatContext context); - - /** - * Extension point for subclasses. Inspect the context and update the state - * of a counter in whatever way is appropriate. This will be added to the - * session-level counter if {@link #setUseParent(boolean)} is true. - * - * @param context the current context. - * - * @return the change in the value of the counter (default 0). - */ - protected int doUpdate(RepeatContext context) { - return 0; - } - - /* - * (non-Javadoc) - * @see org.springframework.batch.repeat.policy.CompletionPolicySupport#isComplete(org.springframework.batch.repeat.BatchContext) - */ - final public boolean isComplete(RepeatContext context) { - int count = ((CountingBatchContext) context).getCounter().getCount(); - return count >= maxCount; - } - - /* - * (non-Javadoc) - * @see org.springframework.batch.repeat.policy.CompletionPolicySupport#start(org.springframework.batch.repeat.BatchContext) - */ - public RepeatContext start(RepeatContext parent) { - return new CountingBatchContext(parent); - } - - /* - * (non-Javadoc) - * @see org.springframework.batch.repeat.policy.CompletionPolicySupport#update(org.springframework.batch.repeat.BatchContext) - */ - final public void update(RepeatContext context) { - super.update(context); - int delta = doUpdate(context); - ((CountingBatchContext) context).getCounter().increment(delta); - } - - protected class CountingBatchContext extends RepeatContextSupport { - - RepeatContextCounter counter; - - public CountingBatchContext(RepeatContext parent) { - super(parent); - counter = new RepeatContextCounter(this, COUNT, useParent); - } - - public RepeatContextCounter getCounter() { - return counter; - } - - } -} diff --git a/src/main/java/org/springframework/repeat/policy/DefaultResultCompletionPolicy.java b/src/main/java/org/springframework/repeat/policy/DefaultResultCompletionPolicy.java deleted file mode 100644 index 782c7b7..0000000 --- a/src/main/java/org/springframework/repeat/policy/DefaultResultCompletionPolicy.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import org.springframework.repeat.CompletionPolicy; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; - -/** - * Very simple {@link CompletionPolicy} that bases its decision on the result of - * a batch operation. If the result is null or not continuable according to the - * {@link RepeatStatus} the batch is complete, otherwise not. - * - * @author Dave Syer - * - */ -public class DefaultResultCompletionPolicy extends CompletionPolicySupport { - - /** - * True if the result is null, or a {@link RepeatStatus} indicating - * completion. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(org.springframework.repeat.RepeatContext, - * RepeatStatus) - */ - public boolean isComplete(RepeatContext context, RepeatStatus result) { - return (result == null || !result.isContinuable()); - } - - /** - * Always false. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(org.springframework.repeat.RepeatContext) - */ - public boolean isComplete(RepeatContext context) { - return false; - } - -} diff --git a/src/main/java/org/springframework/repeat/policy/SimpleCompletionPolicy.java b/src/main/java/org/springframework/repeat/policy/SimpleCompletionPolicy.java deleted file mode 100644 index d0aa862..0000000 --- a/src/main/java/org/springframework/repeat/policy/SimpleCompletionPolicy.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.context.RepeatContextSupport; -import org.springframework.repeat.support.RepeatTemplate; -import org.springframework.util.ClassUtils; - -/** - * Policy for terminating a batch after a fixed number of operations. Internal - * state is maintained and a counter incremented, so successful use of this - * policy requires that isComplete() is only called once per batch item. Using - * the standard {@link RepeatTemplate} should ensure this contract is kept, but it needs - * to be carefully monitored. - * - * @author Dave Syer - * - */ -public class SimpleCompletionPolicy extends DefaultResultCompletionPolicy { - - public static final int DEFAULT_CHUNK_SIZE = 5; - - int chunkSize = 0; - - public SimpleCompletionPolicy() { - this(DEFAULT_CHUNK_SIZE); - } - - public SimpleCompletionPolicy(int chunkSize) { - super(); - this.chunkSize = chunkSize; - } - - public void setChunkSize(int chunkSize) { - this.chunkSize = chunkSize; - } - - /** - * Reset the counter. - * - * @see org.springframework.repeat.CompletionPolicy#start(RepeatContext) - */ - public RepeatContext start(RepeatContext context) { - return new SimpleTerminationContext(context); - } - - /** - * Terminate if the chunk size has been reached, or the result is null. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(RepeatContext, - * RepeatStatus) - * @throws RuntimeException (normally terminating the batch) if the result is - * itself an exception. - */ - public boolean isComplete(RepeatContext context, RepeatStatus result) { - return super.isComplete(context, result) || ((SimpleTerminationContext) context).isComplete(); - } - - /** - * Terminate if the chunk size has been reached. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(RepeatContext) - */ - public boolean isComplete(RepeatContext context) { - return ((SimpleTerminationContext) context).isComplete(); - } - - /** - * Increment the counter in the context. - * - * @see org.springframework.repeat.CompletionPolicy#update(RepeatContext) - */ - public void update(RepeatContext context) { - ((SimpleTerminationContext) context).update(); - } - - protected class SimpleTerminationContext extends RepeatContextSupport { - - public SimpleTerminationContext(RepeatContext context) { - super(context); - } - - public void update() { - increment(); - } - - public boolean isComplete() { - return getStartedCount() >= chunkSize; - } - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - public String toString() { - return ClassUtils.getShortName(SimpleCompletionPolicy.class)+": chunkSize="+chunkSize; - } - -} diff --git a/src/main/java/org/springframework/repeat/policy/TimeoutTerminationPolicy.java b/src/main/java/org/springframework/repeat/policy/TimeoutTerminationPolicy.java deleted file mode 100644 index daf6485..0000000 --- a/src/main/java/org/springframework/repeat/policy/TimeoutTerminationPolicy.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.context.RepeatContextSupport; - -/** - * Termination policy that times out after a fixed period. Allows graceful exit - * from a batch if the latest result comes in after the timeout expires (i.e. - * does not throw a timeout exception).
- * - * N.B. It may often be the case that the batch governed by this policy will be - * transactional, and the transaction might have its own timeout. In this case - * the transaction might throw a timeout exception on commit if its timeout - * threshold is lower than the termination policy. - * - * @author Dave Syer - * - */ -public class TimeoutTerminationPolicy extends CompletionPolicySupport { - - /** - * Default timeout value in millisecs (the value equivalent to 30 seconds). - */ - public static final long DEFAULT_TIMEOUT = 30000L; - - private long timeout = DEFAULT_TIMEOUT; - - /** - * Default constructor. - */ - public TimeoutTerminationPolicy() { - super(); - } - - /** - * Construct a {@link TimeoutTerminationPolicy} with the specified timeout - * value (in milliseconds). - * - * @param timeout - */ - public TimeoutTerminationPolicy(long timeout) { - super(); - this.timeout = timeout; - } - - /** - * Check the timeout and complete gracefully if it has expires. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(org.springframework.repeat.RepeatContext) - */ - @Override - public boolean isComplete(RepeatContext context) { - return ((TimeoutBatchContext) context).isComplete(); - } - - /** - * Start the clock on the timeout. - * - * @see org.springframework.repeat.CompletionPolicy#start(RepeatContext) - */ - @Override - public RepeatContext start(RepeatContext context) { - return new TimeoutBatchContext(context); - } - - protected class TimeoutBatchContext extends RepeatContextSupport { - - private volatile long time = System.currentTimeMillis(); - - private final long timeout = TimeoutTerminationPolicy.this.timeout; - - public TimeoutBatchContext(RepeatContext context) { - super(context); - } - - public boolean isComplete() { - return (System.currentTimeMillis() - time) > timeout; - } - - } - -} diff --git a/src/main/java/org/springframework/repeat/policy/package.html b/src/main/java/org/springframework/repeat/policy/package.html deleted file mode 100644 index e30f24f..0000000 --- a/src/main/java/org/springframework/repeat/policy/package.html +++ /dev/null @@ -1,7 +0,0 @@ - - -

-Infrastructure implementations of repeat policy concerns. -

- - diff --git a/src/main/java/org/springframework/repeat/support/RepeatInternalState.java b/src/main/java/org/springframework/repeat/support/RepeatInternalState.java deleted file mode 100644 index 7767048..0000000 --- a/src/main/java/org/springframework/repeat/support/RepeatInternalState.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import java.util.Collection; - -/** - * Internal interface for extensions of {@link RepeatTemplate}. - * - * @author Dave Syer - * - */ -public interface RepeatInternalState { - - /** - * Returns a mutable collection of exceptions that have occurred in the - * current repeat context. Clients are expected to mutate this collection. - * - * @return the collection of exceptions being accumulated - */ - Collection getThrowables(); - -} diff --git a/src/main/java/org/springframework/repeat/support/RepeatInternalStateSupport.java b/src/main/java/org/springframework/repeat/support/RepeatInternalStateSupport.java deleted file mode 100644 index d4dc2c5..0000000 --- a/src/main/java/org/springframework/repeat/support/RepeatInternalStateSupport.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -public class RepeatInternalStateSupport implements RepeatInternalState { - - // Accumulation of failed results. - private final Set throwables = new HashSet(); - - /* (non-Javadoc) - * @see org.springframework.batch.repeat.support.BatchInternalState#getThrowables() - */ - public Collection getThrowables() { - return throwables; - } - -} diff --git a/src/main/java/org/springframework/repeat/support/RepeatSynchronizationManager.java b/src/main/java/org/springframework/repeat/support/RepeatSynchronizationManager.java deleted file mode 100644 index 33cdc32..0000000 --- a/src/main/java/org/springframework/repeat/support/RepeatSynchronizationManager.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatOperations; - -/** - * Global variable support for repeat clients. Normally it is not necessary for - * clients to be aware of the surrounding environment because a - * {@link RepeatCallback} can always use the context it is passed by the - * enclosing {@link RepeatOperations}. But occasionally it might be helpful to - * have lower level access to the ongoing {@link RepeatContext} so we provide a - * global accessor here. The mutator methods ({@link #clear()} and - * {@link #register(RepeatContext)} should not be used except internally by - * {@link RepeatOperations} implementations. - * - * @author Dave Syer - * - */ -public final class RepeatSynchronizationManager { - - private static final ThreadLocal contextHolder = new ThreadLocal(); - - private RepeatSynchronizationManager() { - } - - /** - * Getter for the current context. A context is shared by all items in the - * batch, so this method is intended to return the same context object - * independent of whether the callback is running synchronously or - * asynchronously with the surrounding {@link RepeatOperations}. - * - * @return the current {@link RepeatContext} or null if there is none (if we - * are not in a batch). - */ - public static RepeatContext getContext() { - return contextHolder.get(); - } - - /** - * Convenience method to set the current repeat operation to complete if it - * exists. - */ - public static void setCompleteOnly() { - RepeatContext context = getContext(); - if (context != null) { - context.setCompleteOnly(); - } - } - - /** - * Method for registering a context - should only be used by - * {@link RepeatOperations} implementations to ensure that - * {@link #getContext()} always returns the correct value. - * - * @param context a new context at the start of a batch. - * @return the old value if there was one. - */ - public static RepeatContext register(RepeatContext context) { - RepeatContext oldSession = getContext(); - RepeatSynchronizationManager.contextHolder.set(context); - return oldSession; - } - - /** - * Clear the current context at the end of a batch - should only be used by - * {@link RepeatOperations} implementations. - * - * @return the old value if there was one. - */ - public static RepeatContext clear() { - RepeatContext context = getContext(); - RepeatSynchronizationManager.contextHolder.set(null); - return context; - } - - /** - * Set current session and all ancestors (via parent) to complete., - */ - public static void setAncestorsCompleteOnly() { - RepeatContext context = getContext(); - while (context != null) { - context.setCompleteOnly(); - context = context.getParent(); - } - } - -} diff --git a/src/main/java/org/springframework/repeat/support/RepeatTemplate.java b/src/main/java/org/springframework/repeat/support/RepeatTemplate.java deleted file mode 100644 index 05a8d08..0000000 --- a/src/main/java/org/springframework/repeat/support/RepeatTemplate.java +++ /dev/null @@ -1,476 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.repeat.CompletionPolicy; -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatException; -import org.springframework.repeat.RepeatListener; -import org.springframework.repeat.RepeatOperations; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.exception.DefaultExceptionHandler; -import org.springframework.repeat.exception.ExceptionHandler; -import org.springframework.repeat.policy.DefaultResultCompletionPolicy; -import org.springframework.util.Assert; - -/** - * Simple implementation and base class for batch templates implementing - * {@link RepeatOperations}. Provides a framework including interceptors and - * policies. Subclasses just need to provide a method that gets the next result - * and one that waits for all the results to be returned from concurrent - * processes or threads.
- * - * N.B. the template accumulates thrown exceptions during the iteration, and - * they are all processed together when the main loop ends (i.e. finished - * processing the items). Clients that do not want to stop execution when an - * exception is thrown can use a specific {@link CompletionPolicy} that does not - * finish when exceptions are received. This is not the default behaviour.
- * - * Clients that want to take some business action when an exception is thrown by - * the {@link RepeatCallback} can consider using a custom {@link RepeatListener} - * instead of trying to customise the {@link CompletionPolicy}. This is - * generally a friendlier interface to implement, and the - * {@link RepeatListener#after(RepeatContext, RepeatStatus)} method is passed in - * the result of the callback, which would be an instance of {@link Throwable} - * if the business processing had thrown an exception. If the exception is not - * to be propagated to the caller, then a non-default {@link CompletionPolicy} - * needs to be provided as well, but that could be off the shelf, with the - * business action implemented only in the interceptor. - * - * @author Dave Syer - * - */ -public class RepeatTemplate implements RepeatOperations { - - protected Log logger = LogFactory.getLog(getClass()); - - private RepeatListener[] listeners = new RepeatListener[] {}; - - private CompletionPolicy completionPolicy = new DefaultResultCompletionPolicy(); - - private ExceptionHandler exceptionHandler = new DefaultExceptionHandler(); - - /** - * Set the listeners for this template, registering them for callbacks at - * appropriate times in the iteration. - * - * @param listeners - */ - public void setListeners(RepeatListener[] listeners) { - this.listeners = Arrays.asList(listeners).toArray(new RepeatListener[listeners.length]); - } - - /** - * Register an additional listener. - * - * @param listener - */ - public void registerListener(RepeatListener listener) { - List list = new ArrayList(Arrays.asList(listeners)); - list.add(listener); - listeners = (RepeatListener[]) list.toArray(new RepeatListener[list.size()]); - } - - /** - * Setter for exception handler strategy. The exception handler is called at - * the end of a batch, after the {@link CompletionPolicy} has determined - * that the batch is complete. By default all exceptions are re-thrown. - * - * @see ExceptionHandler - * @see DefaultExceptionHandler - * @see #setCompletionPolicy(CompletionPolicy) - * - * @param exceptionHandler the {@link ExceptionHandler} to use. - */ - public void setExceptionHandler(ExceptionHandler exceptionHandler) { - this.exceptionHandler = exceptionHandler; - } - - /** - * Setter for policy to decide when the batch is complete. The default is to - * complete normally when the callback returns a {@link RepeatStatus} which - * is not marked as continuable, and abnormally when the callback throws an - * exception (but the decision to re-throw the exception is deferred to the - * {@link ExceptionHandler}). - * - * @see #setExceptionHandler(ExceptionHandler) - * - * @param terminationPolicy a TerminationPolicy. - * @throws IllegalArgumentException if the argument is null - */ - public void setCompletionPolicy(CompletionPolicy terminationPolicy) { - Assert.notNull(terminationPolicy); - this.completionPolicy = terminationPolicy; - } - - /** - * Execute the batch callback until the completion policy decides that we - * are finished. Wait for the whole batch to finish before returning even if - * the task executor is asynchronous. - * - * @see org.springframework.repeat.RepeatOperations#iterate(org.springframework.repeat.RepeatCallback) - */ - public RepeatStatus iterate(RepeatCallback callback) { - - RepeatContext outer = RepeatSynchronizationManager.getContext(); - - RepeatStatus result = RepeatStatus.CONTINUABLE; - try { - // This works with an asynchronous TaskExecutor: the - // interceptors have to wait for the child processes. - result = executeInternal(callback); - } - finally { - RepeatSynchronizationManager.clear(); - if (outer != null) { - RepeatSynchronizationManager.register(outer); - } - } - - return result; - } - - /** - * Internal convenience method to loop over interceptors and batch - * callbacks. - * - * @param callback the callback to process each element of the loop. - * - * @return the aggregate of {@link ContinuationPolicy#canContinue(Object)} - * for all the results from the callback. - * - */ - private RepeatStatus executeInternal(final RepeatCallback callback) { - - // Reset the termination policy if there is one... - RepeatContext context = start(); - - // Make sure if we are already marked complete before we start then no - // processing takes place. - boolean running = !isMarkedComplete(context); - - for (int i = 0; i < listeners.length; i++) { - RepeatListener interceptor = listeners[i]; - interceptor.open(context); - running = running && !isMarkedComplete(context); - if (!running) - break; - } - - // Return value, default is to allow continued processing. - RepeatStatus result = RepeatStatus.CONTINUABLE; - - RepeatInternalState state = createInternalState(context); - // This is the list of exceptions thrown by all active callbacks - Collection throwables = state.getThrowables(); - // Keep a separate list of exceptions we handled that need to be - // rethrown - Collection deferred = new ArrayList(); - - try { - - while (running) { - - /* - * Run the before interceptors here, not in the task executor so - * that they all happen in the same thread - it's easier for - * tracking batch status, amongst other things. - */ - for (int i = 0; i < listeners.length; i++) { - RepeatListener interceptor = listeners[i]; - interceptor.before(context); - // Allow before interceptors to veto the batch by setting - // flag. - running = running && !isMarkedComplete(context); - } - - // Check that we are still running (should always be true) ... - if (running) { - - try { - - result = getNextResult(context, callback, state); - executeAfterInterceptors(context, result); - - } - catch (Throwable throwable) { - doHandle(throwable, context, deferred); - } - - // N.B. the order may be important here: - if (isComplete(context, result) || isMarkedComplete(context) || !deferred.isEmpty()) { - running = false; - } - - } - - } - - result = result.and(waitForResults(state)); - for (Throwable throwable : throwables) { - doHandle(throwable, context, deferred); - } - - // Explicitly drop any references to internal state... - state = null; - - } - /* - * No need for explicit catch here - if the business processing threw an - * exception it was already handled by the helper methods. An exception - * here is necessarily fatal. - */ - finally { - - try { - - if (!deferred.isEmpty()) { - Throwable throwable = (Throwable) deferred.iterator().next(); - logger.debug("Handling fatal exception explicitly (rethrowing first of " + deferred.size() + "): " - + throwable.getClass().getName() + ": " + throwable.getMessage()); - rethrow(throwable); - } - - } - finally { - - try { - for (int i = listeners.length; i-- > 0;) { - RepeatListener interceptor = listeners[i]; - interceptor.close(context); - } - } - finally { - context.close(); - } - - } - - } - - return result; - - } - - private void doHandle(Throwable throwable, RepeatContext context, Collection deferred) { - // An exception alone is not sufficient grounds for not - // continuing - Throwable unwrappedThrowable = unwrapIfRethrown(throwable); - try { - - for (int i = listeners.length; i-- > 0;) { - RepeatListener interceptor = listeners[i]; - // This is not an error - only log at debug - // level. - logger.debug("Exception intercepted (" + (i + 1) + " of " + listeners.length + ")", unwrappedThrowable); - interceptor.onError(context, unwrappedThrowable); - } - - logger.debug("Handling exception: " + throwable.getClass().getName() + ", caused by: " - + unwrappedThrowable.getClass().getName() + ": " + unwrappedThrowable.getMessage()); - exceptionHandler.handleException(context, unwrappedThrowable); - - } - catch (Throwable handled) { - deferred.add(handled); - } - } - - /** - * Re-throws the original throwable if it is unchecked, wraps checked - * exceptions into {@link RepeatException}. - */ - private static void rethrow(Throwable throwable) throws RuntimeException { - if (throwable instanceof Error) { - throw (Error) throwable; - } - else if (throwable instanceof RuntimeException) { - throw (RuntimeException) throwable; - } - else { - throw new RepeatException("Exception in batch process", throwable); - } - } - - /** - * Unwraps the throwable if it has been wrapped by - * {@link #rethrow(Throwable)}. - */ - private static Throwable unwrapIfRethrown(Throwable throwable) { - if (throwable instanceof RepeatException) { - return throwable.getCause(); - } - else { - return throwable; - } - } - - /** - * Create an internal state object that is used to store data needed - * internally in the scope of an iteration. Used by subclasses to manage the - * queueing and retrieval of asynchronous results. The default just provides - * an accumulation of Throwable instances for processing at the end of the - * batch. - * - * @param context the current {@link RepeatContext} - * @return a {@link RepeatInternalState} instance. - * - * @see RepeatTemplate#waitForResults(RepeatInternalState) - */ - protected RepeatInternalState createInternalState(RepeatContext context) { - return new RepeatInternalStateSupport(); - } - - /** - * Get the next completed result, possibly executing several callbacks until - * one finally finishes. Normally a subclass would have to override both - * this method and {@link #createInternalState(RepeatContext)} because the - * implementation of this method would rely on the details of the internal - * state. - * - * @param context current BatchContext. - * @param callback the callback to execute. - * @param state maintained by the implementation. - * @return a finished result. - * - * @see #isComplete(RepeatContext) - * @see #createInternalState(RepeatContext) - */ - protected RepeatStatus getNextResult(RepeatContext context, RepeatCallback callback, RepeatInternalState state) - throws Throwable { - update(context); - if (logger.isDebugEnabled()) { - logger.debug("Repeat operation about to start at count=" + context.getStartedCount()); - } - return callback.doInIteration(context); - - } - - /** - * If necessary, wait for results to come back from remote or concurrent - * processes. By default does nothing and returns true. - * - * @param state the internal state. - * @return true if {@link #canContinue(RepeatStatus)} is true for all - * results retrieved. - */ - protected boolean waitForResults(RepeatInternalState state) { - // no-op by default - return true; - } - - /** - * Check return value from batch operation. - * - * @param value the last callback result. - * @return true if the value is {@link RepeatStatus#CONTINUABLE}. - */ - protected final boolean canContinue(RepeatStatus value) { - return ((RepeatStatus) value).isContinuable(); - } - - private boolean isMarkedComplete(RepeatContext context) { - boolean complete = context.isCompleteOnly(); - if (context.getParent() != null) { - complete = complete || isMarkedComplete(context.getParent()); - } - if (complete) { - logger.debug("Repeat is complete according to context alone."); - } - return complete; - - } - - /** - * Convenience method to execute after interceptors on a callback result. - * - * @param context the current batch context. - * @param value the result of the callback to process. - */ - protected void executeAfterInterceptors(final RepeatContext context, RepeatStatus value) { - - // Don't re-throw exceptions here: let the exception handler deal with - // that... - - if (value != null && value.isContinuable()) { - for (int i = listeners.length; i-- > 0;) { - RepeatListener interceptor = listeners[i]; - interceptor.after(context, value); - } - - } - - } - - /** - * Delegate to the {@link CompletionPolicy}. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(RepeatContext, - * RepeatStatus) - */ - protected boolean isComplete(RepeatContext context, RepeatStatus result) { - boolean complete = completionPolicy.isComplete(context, result); - if (complete) { - logger.debug("Repeat is complete according to policy and result value."); - } - return complete; - } - - /** - * Delegate to {@link CompletionPolicy}. - * - * @see org.springframework.repeat.CompletionPolicy#isComplete(RepeatContext) - */ - protected boolean isComplete(RepeatContext context) { - boolean complete = completionPolicy.isComplete(context); - if (complete) { - logger.debug("Repeat is complete according to policy alone not including result."); - } - return complete; - } - - /** - * Delegate to the {@link CompletionPolicy}. - * - * @see org.springframework.repeat.CompletionPolicy#start(RepeatContext) - */ - protected RepeatContext start() { - RepeatContext parent = RepeatSynchronizationManager.getContext(); - RepeatContext context = completionPolicy.start(parent); - RepeatSynchronizationManager.register(context); - logger.debug("Starting repeat context."); - return context; - } - - /** - * Delegate to the {@link CompletionPolicy}. - * - * @see org.springframework.repeat.CompletionPolicy#update(RepeatContext) - */ - protected void update(RepeatContext context) { - completionPolicy.update(context); - } - -} diff --git a/src/main/java/org/springframework/repeat/support/ResultHolder.java b/src/main/java/org/springframework/repeat/support/ResultHolder.java deleted file mode 100644 index a2d73be..0000000 --- a/src/main/java/org/springframework/repeat/support/ResultHolder.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; - -/** - * Interface for result holder. - * - * @author Dave Syer - */ -interface ResultHolder { - /** - * Get the result for client from this holder. Does not block if none is - * available yet. - * - * @return the result, or null if there is none. - * @throws IllegalStateException - */ - RepeatStatus getResult(); - - /** - * Get the error for client from this holder if any. Does not block if - * none is available yet. - * - * @return the error, or null if there is none. - * @throws IllegalStateException - */ - Throwable getError(); - - /** - * Get the context in which the result evaluation is executing. - * - * @return the context of the result evaluation. - */ - RepeatContext getContext(); -} \ No newline at end of file diff --git a/src/main/java/org/springframework/repeat/support/ResultHolderResultQueue.java b/src/main/java/org/springframework/repeat/support/ResultHolderResultQueue.java deleted file mode 100644 index 3e16597..0000000 --- a/src/main/java/org/springframework/repeat/support/ResultHolderResultQueue.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2002-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import java.util.Comparator; -import java.util.NoSuchElementException; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.PriorityBlockingQueue; -import java.util.concurrent.Semaphore; - -import org.springframework.repeat.RepeatStatus; - -/** - * An implementation of the {@link ResultQueue} that throttles the number of - * expected results, limiting it to a maximum at any given time. - * - * @author Dave Syer - */ -public class ResultHolderResultQueue implements ResultQueue { - - // Accumulation of result objects as they finish. - private final BlockingQueue results; - - // Accumulation of dummy objects flagging expected results in the future. - private final Semaphore waits; - - private final Object lock = new Object(); - - private volatile int count = 0; - - /** - * @param throttleLimit the maximum number of results that can be expected - * at any given time. - */ - public ResultHolderResultQueue(int throttleLimit) { - results = new PriorityBlockingQueue(throttleLimit, new ResultHolderComparator()); - waits = new Semaphore(throttleLimit); - } - - public boolean isEmpty() { - return results.isEmpty(); - } - - /* - * (non-Javadoc) - * - * @see org.springframework.batch.repeat.support.ResultQueue#isExpecting() - */ - public boolean isExpecting() { - // Base the decision about whether we expect more results on a - // counter of the number of expected results actually collected. - // Do not synchronize! Otherwise put and expect can deadlock. - return count > 0; - } - - /** - * Tell the queue to expect one more result. Blocks until a new result is - * available if already expecting too many (as determined by the throttle - * limit). - * - * @see ResultQueue#expect() - */ - public void expect() throws InterruptedException { - waits.acquire(); - // Don't acquire the lock in a synchronized block - might deadlock - synchronized (lock) { - count++; - } - } - - public void put(ResultHolder holder) throws IllegalArgumentException { - if (!isExpecting()) { - throw new IllegalArgumentException("Not expecting a result. Call expect() before put()."); - } - results.add(holder); - // Take from the waits queue now to allow another result to - // accumulate. But don't decrement the counter. - waits.release(); - synchronized (lock) { - lock.notifyAll(); - } - } - - /** - * Get the next result as soon as it becomes available.
- *
- * Release result immediately if: - *
    - *
  • There is a result that is continuable.
  • - *
- * Otherwise block if either: - *
    - *
  • There is no result (as per contract of {@link ResultQueue}).
  • - *
  • The number of results is less than the number expected.
  • - *
- * Error if either: - *
    - *
  • Not expecting.
  • - *
  • Interrupted.
  • - *
- * - * @see ResultQueue#take() - */ - public ResultHolder take() throws NoSuchElementException, InterruptedException { - if (!isExpecting()) { - throw new NoSuchElementException("Not expecting a result. Call expect() before take()."); - } - ResultHolder value; - synchronized (lock) { - value = results.take(); - if (isContinuable(value)) { - // Decrement the counter only when the result is collected. - count--; - return value; - } - } - results.put(value); - synchronized (lock) { - while (count > results.size()) { - lock.wait(); - } - value = results.take(); - count--; - } - return value; - } - - private boolean isContinuable(ResultHolder value) { - return value.getResult() != null && value.getResult().isContinuable(); - } - - /** - * Compares ResultHolders so that one that is continuable ranks lowest. - * - * @author Dave Syer - * - */ - private static class ResultHolderComparator implements Comparator { - public int compare(ResultHolder h1, ResultHolder h2) { - RepeatStatus result1 = h1.getResult(); - RepeatStatus result2 = h2.getResult(); - if (result1 == null && result2 == null) { - return 0; - } - if (result1 == null) { - return -1; - } - else if (result2 == null) { - return 1; - } - if ((result1.isContinuable() && result2.isContinuable()) - || (!result1.isContinuable() && !result2.isContinuable())) { - return 0; - } - if (result1.isContinuable()) { - return -1; - } - return 1; - } - } - -} diff --git a/src/main/java/org/springframework/repeat/support/ResultQueue.java b/src/main/java/org/springframework/repeat/support/ResultQueue.java deleted file mode 100644 index 55a85d4..0000000 --- a/src/main/java/org/springframework/repeat/support/ResultQueue.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2002-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import java.util.NoSuchElementException; -import java.util.concurrent.BlockingQueue; - -import org.springframework.core.task.TaskExecutor; - -/** - * Abstraction for queue of {@link ResultHolder} objects. Acts a bit likeT a - * {@link BlockingQueue} with the ability to count the number of items it - * expects to ever hold. When clients schedule an item to be added they call - * {@link #expect()}, and then collect the result later with {@link #take()}. - * Result providers in another thread call {@link #put(Object)} to notify the - * expecting client of a new result. - * - * @author Dave Syer - * @author Ben Hale - */ -interface ResultQueue { - - /** - * In a master-slave pattern, the master calls this method paired with - * {@link #take()} to manage the flow of items. Normally a task is submitted - * for processing in another thread, at which point the master uses this - * method to keep track of the number of expected results. It has the - * personality of an counter increment, rather than a work queue, which is - * usually managed elsewhere, e.g. by a {@link TaskExecutor}.

- * Implementations may choose to block here, if they need to limit the - * number or rate of tasks being submitted. - * - * @throws InterruptedException if the call blocks and is then interrupted. - */ - void expect() throws InterruptedException; - - /** - * Once it is expecting a result, clients call this method to satisfy the - * expectation. In a master-worker pattern, the workers call this method to - * deposit the result of a finished task on the queue for collection. - * - * @param result the result for later collection. - * - * @throws IllegalArgumentException if the queue is not expecting a new - * result - */ - void put(T result) throws IllegalArgumentException; - - /** - * Gets the next available result, blocking if there are none yet available. - * - * @return a result previously deposited - * - * @throws NoSuchElementException if there is no result expected - * @throws InterruptedException if the operation is interrupted while - * waiting - */ - T take() throws NoSuchElementException, InterruptedException; - - /** - * Used by master thread to verify that there are results available from - * {@link #take()} without possibly having to block and wait. - * - * @return true if there are no results available - */ - boolean isEmpty(); - - /** - * Check if any results are expected. Usually used by master thread to drain - * queue when it is finished. - * - * @return true if more results are expected, but possibly not yet - * available. - */ - public boolean isExpecting(); - -} diff --git a/src/main/java/org/springframework/repeat/support/TaskExecutorRepeatTemplate.java b/src/main/java/org/springframework/repeat/support/TaskExecutorRepeatTemplate.java deleted file mode 100644 index dc57b2b..0000000 --- a/src/main/java/org/springframework/repeat/support/TaskExecutorRepeatTemplate.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import org.springframework.core.task.SyncTaskExecutor; -import org.springframework.core.task.TaskExecutor; -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatException; -import org.springframework.repeat.RepeatOperations; -import org.springframework.repeat.RepeatStatus; -import org.springframework.util.Assert; - -/** - * Provides {@link RepeatOperations} support including interceptors that can be - * used to modify or monitor the behaviour at run time.
- * - * This implementation is sufficient to be used to configure transactional - * behaviour for each item by making the {@link RepeatCallback} transactional, - * or for the whole batch by making the execute method transactional (but only - * then if the task executor is synchronous).
- * - * This class is thread safe if its collaborators are thread safe (interceptors, - * terminationPolicy, callback). Normally this will be the case, but clients - * need to be aware that if the task executor is asynchronous, then the other - * collaborators should be also. In particular the {@link RepeatCallback} that - * is wrapped in the execute method must be thread safe - often it is based on - * some form of data source, which itself should be both thread safe and - * transactional (multiple threads could be accessing it at any given time, and - * each thread would have its own transaction).
- * - * @author Dave Syer - * - */ -public class TaskExecutorRepeatTemplate extends RepeatTemplate { - - /** - * Default limit for maximum number of concurrent unfinished results allowed - * by the template. - * {@link #getNextResult(RepeatContext, RepeatCallback, RepeatInternalState)} - * . - */ - public static final int DEFAULT_THROTTLE_LIMIT = 4; - - private int throttleLimit = DEFAULT_THROTTLE_LIMIT; - - private TaskExecutor taskExecutor = new SyncTaskExecutor(); - - /** - * Public setter for the throttle limit. The throttle limit is the largest - * number of concurrent tasks that can be executing at one time - if a new - * task arrives and the throttle limit is breached we wait for one of the - * executing tasks to finish before submitting the new one to the - * {@link TaskExecutor}. Default value is {@link #DEFAULT_THROTTLE_LIMIT}. - * N.B. when used with a thread pooled {@link TaskExecutor} the thread pool - * might prevent the throttle limit actually being reached (so make the core - * pool size larger than the throttle limit if possible). - * - * @param throttleLimit the throttleLimit to set. - */ - public void setThrottleLimit(int throttleLimit) { - this.throttleLimit = throttleLimit; - } - - /** - * Setter for task executor to be used to run the individual item callbacks. - * - * @param taskExecutor a TaskExecutor - * @throws IllegalArgumentException if the argument is null - */ - public void setTaskExecutor(TaskExecutor taskExecutor) { - Assert.notNull(taskExecutor); - this.taskExecutor = taskExecutor; - } - - /** - * Use the {@link #setTaskExecutor(TaskExecutor)} to generate a result. The - * internal state in this case is a queue of unfinished result holders of - * type {@link ResultHolder}. The holder with the return value should not be - * on the queue when this method exits. The queue is scoped in the calling - * method so there is no need to synchronize access. - * - */ - protected RepeatStatus getNextResult(RepeatContext context, RepeatCallback callback, RepeatInternalState state) - throws Throwable { - - ExecutingRunnable runnable = null; - - ResultQueue queue = ((ResultQueueInternalState) state).getResultQueue(); - - do { - - /* - * Wrap the callback in a runnable that will add its result to the - * queue when it is ready. - */ - runnable = new ExecutingRunnable(callback, context, queue); - - /** - * Tell the runnable that it can expect a result. This could have - * been in-lined with the constructor, but it might block, so it's - * better to do it here, since we have the option (it's a private - * class). - */ - runnable.expect(); - - /* - * Start the task possibly concurrently / in the future. - */ - taskExecutor.execute(runnable); - - /* - * Allow termination policy to update its state. This must happen - * immediately before or after the call to the task executor. - */ - update(context); - - /* - * Keep going until we get a result that is finished, or early - * termination... - */ - } while (queue.isEmpty() && !isComplete(context)); - - /* - * N.B. If the queue is empty then take() blocks until a result appears, - * and there must be at least one because we just submitted one to the - * task executor. - */ - ResultHolder result = queue.take(); - if (result.getError() != null) { - throw result.getError(); - } - return result.getResult(); - } - - /** - * Wait for all the results to appear on the queue and execute the after - * interceptors for each one. - * - * @see org.springframework.repeat.support.RepeatTemplate#waitForResults(org.springframework.repeat.support.RepeatInternalState) - */ - protected boolean waitForResults(RepeatInternalState state) { - - ResultQueue queue = ((ResultQueueInternalState) state).getResultQueue(); - - boolean result = true; - - while (queue.isExpecting()) { - - /* - * Careful that no runnables that are not going to finish ever get - * onto the queue, else this may block forever. - */ - ResultHolder future; - try { - future = (ResultHolder) queue.take(); - } - catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RepeatException("InterruptedException while waiting for result."); - } - - if (future.getError() != null) { - state.getThrowables().add(future.getError()); - } - else { - RepeatStatus status = future.getResult(); - result = result && canContinue(status); - executeAfterInterceptors(future.getContext(), status); - } - - } - - Assert.state(queue.isEmpty(), "Future results queue should be empty at end of batch."); - - return result; - } - - protected RepeatInternalState createInternalState(RepeatContext context) { - // Queue of pending results: - return new ResultQueueInternalState(throttleLimit); - } - - /** - * A runnable that puts its result on a queue when it is done. - * - * @author Dave Syer - * - */ - private class ExecutingRunnable implements Runnable, ResultHolder { - - private final RepeatCallback callback; - - private final RepeatContext context; - - private final ResultQueue queue; - - private volatile RepeatStatus result; - - private volatile Throwable error; - - public ExecutingRunnable(RepeatCallback callback, RepeatContext context, ResultQueue queue) { - - super(); - - this.callback = callback; - this.context = context; - this.queue = queue; - - } - - /** - * Tell the queue to expect a result. - */ - public void expect() { - try { - queue.expect(); - } - catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RepeatException("InterruptedException waiting for to acquire lock on input."); - } - } - - /** - * Execute the batch callback, and store the result, or any exception - * that is thrown for retrieval later by caller. - * - * @see java.lang.Runnable#run() - */ - public void run() { - boolean clearContext = false; - try { - if (RepeatSynchronizationManager.getContext() == null) { - clearContext = true; - RepeatSynchronizationManager.register(context); - } - - if (logger.isDebugEnabled()) { - logger.debug("Repeat operation about to start at count=" + context.getStartedCount()); - } - - result = callback.doInIteration(context); - - } - catch (Exception e) { - error = e; - } - finally { - - if (clearContext) { - RepeatSynchronizationManager.clear(); - } - - queue.put(this); - - } - } - - /** - * Get the result - never blocks because the queue manages waiting for - * the task to finish. - */ - public RepeatStatus getResult() { - return result; - } - - /** - * Get the error - never blocks because the queue manages waiting for - * the task to finish. - */ - public Throwable getError() { - return error; - } - - /** - * Getter for the context. - */ - public RepeatContext getContext() { - return this.context; - } - - } - - /** - * @author Dave Syer - * - */ - private static class ResultQueueInternalState extends RepeatInternalStateSupport { - - private final ResultQueue results; - - /** - * @param throttleLimit the throttle limit for the result queue - */ - public ResultQueueInternalState(int throttleLimit) { - super(); - this.results = new ResultHolderResultQueue(throttleLimit); - } - - /** - * @return the result queue - */ - public ResultQueue getResultQueue() { - return results; - } - - } - -} diff --git a/src/main/java/org/springframework/repeat/support/ThrottleLimitResultQueue.java b/src/main/java/org/springframework/repeat/support/ThrottleLimitResultQueue.java deleted file mode 100644 index dc96536..0000000 --- a/src/main/java/org/springframework/repeat/support/ThrottleLimitResultQueue.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2002-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import java.util.NoSuchElementException; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.Semaphore; - -/** - * An implementation of the {@link ResultQueue} that throttles the number of - * expected results, limiting it to a maximum at any given time. - * - * @author Dave Syer - */ -public class ThrottleLimitResultQueue implements ResultQueue { - - // Accumulation of result objects as they finish. - private final BlockingQueue results; - - // Accumulation of dummy objects flagging expected results in the future. - private final Semaphore waits; - - private final Object lock = new Object(); - - private volatile int count = 0; - - /** - * @param throttleLimit the maximum number of results that can be expected - * at any given time. - */ - public ThrottleLimitResultQueue(int throttleLimit) { - results = new LinkedBlockingQueue(); - waits = new Semaphore(throttleLimit); - } - - public boolean isEmpty() { - return results.isEmpty(); - } - - /* - * (non-Javadoc) - * - * @see org.springframework.batch.repeat.support.ResultQueue#isExpecting() - */ - public boolean isExpecting() { - // Base the decision about whether we expect more results on a - // counter of the number of expected results actually collected. - // Do not synchronize! Otherwise put and expect can deadlock. - return count > 0; - } - - /** - * Tell the queue to expect one more result. Blocks until a new result is - * available if already expecting too many (as determined by the throttle - * limit). - * - * @see ResultQueue#expect() - */ - public void expect() throws InterruptedException { - synchronized (lock) { - waits.acquire(); - count++; - } - } - - public void put(T holder) throws IllegalArgumentException { - if (!isExpecting()) { - throw new IllegalArgumentException("Not expecting a result. Call expect() before put()."); - } - // There should be no need to block here, or to use offer() - results.add(holder); - // Take from the waits queue now to allow another result to - // accumulate. But don't decrement the counter. - waits.release(); - } - - public T take() throws NoSuchElementException, InterruptedException { - if (!isExpecting()) { - throw new NoSuchElementException("Not expecting a result. Call expect() before take()."); - } - T value; - synchronized (lock) { - value = results.take(); - // Decrement the counter only when the result is collected. - count--; - } - return value; - } - -} diff --git a/src/main/java/org/springframework/repeat/support/package.html b/src/main/java/org/springframework/repeat/support/package.html deleted file mode 100644 index 6e3f0ee..0000000 --- a/src/main/java/org/springframework/repeat/support/package.html +++ /dev/null @@ -1,7 +0,0 @@ - - -

-Infrastructure implementations of repeat support concerns. -

- - diff --git a/src/main/java/org/springframework/retry/support/RetrySynchronizationManager.java b/src/main/java/org/springframework/retry/support/RetrySynchronizationManager.java index bacef57..df696e8 100644 --- a/src/main/java/org/springframework/retry/support/RetrySynchronizationManager.java +++ b/src/main/java/org/springframework/retry/support/RetrySynchronizationManager.java @@ -16,7 +16,6 @@ package org.springframework.retry.support; -import org.springframework.repeat.RepeatOperations; import org.springframework.retry.RetryCallback; import org.springframework.retry.RetryContext; import org.springframework.retry.RetryOperations; @@ -52,7 +51,7 @@ public final class RetrySynchronizationManager { /** * Method for registering a context - should only be used by - * {@link RetryOperations} implementations to ensure that + * {@link org.springframework.repeat.RepeatOperations} implementations to ensure that * {@link #getContext()} always returns the correct value. * * @param context the new context to register diff --git a/src/main/java/org/springframework/retry/support/RetryTemplate.java b/src/main/java/org/springframework/retry/support/RetryTemplate.java index ca0b11b..f191c9c 100644 --- a/src/main/java/org/springframework/retry/support/RetryTemplate.java +++ b/src/main/java/org/springframework/retry/support/RetryTemplate.java @@ -23,7 +23,6 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.repeat.RepeatException; import org.springframework.retry.ExhaustedRetryException; import org.springframework.retry.RecoveryCallback; import org.springframework.retry.RetryCallback; @@ -469,7 +468,7 @@ public class RetryTemplate implements RetryOperations { /** * Re-throws the original throwable if it is unchecked, wraps checked - * exceptions into {@link RepeatException}. + * exceptions into {@link RetryException}. */ private static Exception wrapIfNecessary(Throwable throwable) { if (throwable instanceof Error) { diff --git a/src/test/java/org/springframework/repeat/AbstractExceptionTests.java b/src/test/java/org/springframework/repeat/AbstractExceptionTests.java deleted file mode 100644 index 54d7f73..0000000 --- a/src/test/java/org/springframework/repeat/AbstractExceptionTests.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat; - -import junit.framework.TestCase; - -public abstract class AbstractExceptionTests extends TestCase { - - public void testExceptionString() throws Exception { - Exception exception = getException("foo"); - assertEquals("foo", exception.getMessage()); - } - - public void testExceptionStringThrowable() throws Exception { - Exception exception = getException("foo", new IllegalStateException()); - assertEquals("foo", exception.getMessage().substring(0, 3)); - } - - public abstract Exception getException(String msg) throws Exception; - - public abstract Exception getException(String msg, Throwable t) throws Exception; -} diff --git a/src/test/java/org/springframework/repeat/RepeatExceptionTests.java b/src/test/java/org/springframework/repeat/RepeatExceptionTests.java deleted file mode 100644 index b26cd50..0000000 --- a/src/test/java/org/springframework/repeat/RepeatExceptionTests.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat; - -import org.springframework.repeat.RepeatException; - -public class RepeatExceptionTests extends AbstractExceptionTests { - - public Exception getException(String msg) throws Exception { - return new RepeatException(msg); - } - - public Exception getException(String msg, Throwable t) throws Exception { - return new RepeatException(msg, t); - } - - public void testNothing() throws Exception { - // fool coverage tools... - } -} diff --git a/src/test/java/org/springframework/repeat/callback/NestedRepeatCallbackTests.java b/src/test/java/org/springframework/repeat/callback/NestedRepeatCallbackTests.java deleted file mode 100644 index 3562582..0000000 --- a/src/test/java/org/springframework/repeat/callback/NestedRepeatCallbackTests.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.callback; - -import junit.framework.TestCase; - -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.support.RepeatTemplate; - -public class NestedRepeatCallbackTests extends TestCase { - - int count = 0; - - public void testExecute() throws Exception { - NestedRepeatCallback callback = new NestedRepeatCallback(new RepeatTemplate(), new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - count++; - return RepeatStatus.continueIf(count <= 1); - } - }); - RepeatStatus result = callback.doInIteration(null); - assertEquals(2, count); - assertFalse(result.isContinuable()); // False because processing has finished - } -} diff --git a/src/test/java/org/springframework/repeat/context/RepeatContextCounterTests.java b/src/test/java/org/springframework/repeat/context/RepeatContextCounterTests.java deleted file mode 100644 index d17373d..0000000 --- a/src/test/java/org/springframework/repeat/context/RepeatContextCounterTests.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.context; - -import junit.framework.TestCase; - -import org.springframework.repeat.RepeatContext; - -public class RepeatContextCounterTests extends TestCase { - - RepeatContext parent = new RepeatContextSupport(null); - RepeatContext context = new RepeatContextSupport(parent); - - public void testAttributeCreated() { - new RepeatContextCounter(context, "FOO"); - assertTrue(context.hasAttribute("FOO")); - } - - public void testAttributeCreatedWithNullParent() { - new RepeatContextCounter(parent, "FOO", true); - assertTrue(parent.hasAttribute("FOO")); - } - - public void testVanillaIncrement() throws Exception { - RepeatContextCounter counter = new RepeatContextCounter(context, "FOO"); - assertEquals(0, counter.getCount()); - counter.increment(1); - assertEquals(1, counter.getCount()); - counter.increment(2); - assertEquals(3, counter.getCount()); - } - - public void testAttributeCreatedInParent() throws Exception { - new RepeatContextCounter(context, "FOO", true); - assertFalse(context.hasAttribute("FOO")); - assertTrue(parent.hasAttribute("FOO")); - } - - public void testParentIncrement() throws Exception { - RepeatContextCounter counter = new RepeatContextCounter(context, "FOO", true); - assertEquals(0, counter.getCount()); - counter.increment(1); - // now get new context with same parent - counter = new RepeatContextCounter(new RepeatContextSupport(parent), "FOO", true); - assertEquals(1, counter.getCount()); - counter.increment(2); - assertEquals(3, counter.getCount()); - } - -} diff --git a/src/test/java/org/springframework/repeat/context/RepeatContextSupportTests.java b/src/test/java/org/springframework/repeat/context/RepeatContextSupportTests.java deleted file mode 100644 index d89d052..0000000 --- a/src/test/java/org/springframework/repeat/context/RepeatContextSupportTests.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.repeat.context; - -import java.util.ArrayList; -import java.util.List; - -import junit.framework.TestCase; - -/** - * @author dsyer - * - */ -public class RepeatContextSupportTests extends TestCase { - - private List list = new ArrayList(); - - /** - * Test method for {@link org.springframework.repeat.context.RepeatContextSupport#registerDestructionCallback(java.lang.String, java.lang.Runnable)}. - */ - public void testDestructionCallbackSunnyDay() throws Exception { - RepeatContextSupport context = new RepeatContextSupport(null); - context.setAttribute("foo", "FOO"); - context.registerDestructionCallback("foo", new Runnable() { - public void run() { - list.add("bar"); - } - }); - context.close(); - assertEquals(1, list.size()); - assertEquals("bar", list.get(0)); - } - - /** - * Test method for {@link org.springframework.repeat.context.RepeatContextSupport#registerDestructionCallback(java.lang.String, java.lang.Runnable)}. - */ - public void testDestructionCallbackMissingAttribute() throws Exception { - RepeatContextSupport context = new RepeatContextSupport(null); - context.registerDestructionCallback("foo", new Runnable() { - public void run() { - list.add("bar"); - } - }); - context.close(); - // No check for the attribute before executing callback - assertEquals(1, list.size()); - } - - /** - * Test method for {@link org.springframework.repeat.context.RepeatContextSupport#registerDestructionCallback(java.lang.String, java.lang.Runnable)}. - */ - public void testDestructionCallbackWithException() throws Exception { - RepeatContextSupport context = new RepeatContextSupport(null); - context.setAttribute("foo", "FOO"); - context.setAttribute("bar", "BAR"); - context.registerDestructionCallback("bar", new Runnable() { - public void run() { - list.add("spam"); - throw new RuntimeException("fail!"); - } - }); - context.registerDestructionCallback("foo", new Runnable() { - public void run() { - list.add("bar"); - throw new RuntimeException("fail!"); - } - }); - try { - context.close(); - fail("Expected RuntimeException"); - } catch (RuntimeException e) { - // We don't care which one was thrown... - assertEquals("fail!", e.getMessage()); - } - // ...but we do care that both were executed: - assertEquals(2, list.size()); - assertTrue(list.contains("bar")); - assertTrue(list.contains("spam")); - } -} diff --git a/src/test/java/org/springframework/repeat/context/SynchronizedAttributeAccessorTests.java b/src/test/java/org/springframework/repeat/context/SynchronizedAttributeAccessorTests.java deleted file mode 100644 index 3a94bfd..0000000 --- a/src/test/java/org/springframework/repeat/context/SynchronizedAttributeAccessorTests.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.context; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import junit.framework.TestCase; - -import org.springframework.core.AttributeAccessorSupport; - -public class SynchronizedAttributeAccessorTests extends TestCase { - - SynchronizedAttributeAccessor accessor = new SynchronizedAttributeAccessor(); - - public void testHashCode() { - SynchronizedAttributeAccessor another = new SynchronizedAttributeAccessor(); - accessor.setAttribute("foo", "bar"); - another.setAttribute("foo", "bar"); - assertEquals(accessor, another); - assertEquals("Object.hashCode() contract broken", accessor.hashCode(), another.hashCode()); - } - - public void testToStringWithNoAttributes() throws Exception { - assertNotNull(accessor.toString()); - } - - public void testToStringWithAttributes() throws Exception { - accessor.setAttribute("foo", "bar"); - accessor.setAttribute("spam", "bucket"); - assertNotNull(accessor.toString()); - } - - public void testAttributeNames() { - accessor.setAttribute("foo", "bar"); - accessor.setAttribute("spam", "bucket"); - List list = Arrays.asList(accessor.attributeNames()); - assertEquals(2, list.size()); - assertTrue(list.contains("foo")); - } - - public void testEqualsSameType() { - SynchronizedAttributeAccessor another = new SynchronizedAttributeAccessor(); - accessor.setAttribute("foo", "bar"); - another.setAttribute("foo", "bar"); - assertEquals(accessor, another); - } - - public void testEqualsSelf() { - accessor.setAttribute("foo", "bar"); - assertEquals(accessor, accessor); - } - - public void testEqualsWrongType() { - accessor.setAttribute("foo", "bar"); - Map another = Collections.singletonMap("foo", "bar"); - // Accessor and another are instances of unrelated classes, they should - // never be equal... - assertFalse(accessor.equals(another)); - } - - public void testEqualsSupport() { - AttributeAccessorSupport another = new AttributeAccessorSupport() { - }; - accessor.setAttribute("foo", "bar"); - another.setAttribute("foo", "bar"); - assertEquals(accessor, another); - } - - public void testGetAttribute() { - accessor.setAttribute("foo", "bar"); - assertEquals("bar", accessor.getAttribute("foo")); - } - - public void testSetAttributeIfAbsentWhenAlreadyPresent() { - accessor.setAttribute("foo", "bar"); - assertEquals("bar", accessor.setAttributeIfAbsent("foo", "spam")); - } - - public void testSetAttributeIfAbsentWhenNotAlreadyPresent() { - assertEquals(null, accessor.setAttributeIfAbsent("foo", "bar")); - assertEquals("bar", accessor.getAttribute("foo")); - } - - public void testHasAttribute() { - accessor.setAttribute("foo", "bar"); - assertEquals(true, accessor.hasAttribute("foo")); - } - - public void testRemoveAttribute() { - accessor.setAttribute("foo", "bar"); - assertEquals("bar", accessor.getAttribute("foo")); - accessor.removeAttribute("foo"); - assertEquals(null, accessor.getAttribute("foo")); - } - -} diff --git a/src/test/java/org/springframework/repeat/exception/CompositeExceptionHandlerTests.java b/src/test/java/org/springframework/repeat/exception/CompositeExceptionHandlerTests.java deleted file mode 100644 index 54cd8c4..0000000 --- a/src/test/java/org/springframework/repeat/exception/CompositeExceptionHandlerTests.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import java.util.ArrayList; -import java.util.List; - -import junit.framework.TestCase; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.exception.CompositeExceptionHandler; -import org.springframework.repeat.exception.ExceptionHandler; - -public class CompositeExceptionHandlerTests extends TestCase { - - private CompositeExceptionHandler handler = new CompositeExceptionHandler(); - - public void testNewHandler() throws Throwable { - try { - handler.handleException(null, new RuntimeException()); - } - catch (RuntimeException e) { - fail("Unexpected RuntimeException"); - } - } - - public void testDelegation() throws Throwable { - final List list = new ArrayList(); - handler.setHandlers(new ExceptionHandler[] { - new ExceptionHandler() { - public void handleException(RepeatContext context, Throwable throwable) throws RuntimeException { - list.add("1"); - } - }, - new ExceptionHandler() { - public void handleException(RepeatContext context, Throwable throwable) throws RuntimeException { - list.add("2"); - } - } - }); - handler.handleException(null, new RuntimeException()); - assertEquals(2, list.size()); - assertEquals("1", list.get(0)); - assertEquals("2", list.get(1)); - } -} diff --git a/src/test/java/org/springframework/repeat/exception/DefaultExceptionHandlerTests.java b/src/test/java/org/springframework/repeat/exception/DefaultExceptionHandlerTests.java deleted file mode 100644 index 820e9f9..0000000 --- a/src/test/java/org/springframework/repeat/exception/DefaultExceptionHandlerTests.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import junit.framework.TestCase; - -import org.springframework.repeat.RepeatContext; - -public class DefaultExceptionHandlerTests extends TestCase { - - private DefaultExceptionHandler handler = new DefaultExceptionHandler(); - private RepeatContext context = null; - - public void testRuntimeException() throws Throwable { - try { - handler.handleException(context, new RuntimeException("Foo")); - fail("Expected RuntimeException"); - } catch (RuntimeException e) { - assertEquals("Foo", e.getMessage()); - } - } - - public void testError() throws Throwable { - try { - handler.handleException(context, new Error("Foo")); - fail("Expected Error"); - } catch (Error e) { - assertEquals("Foo", e.getMessage()); - } - } -} diff --git a/src/test/java/org/springframework/repeat/exception/LogOrRethrowExceptionHandlerTests.java b/src/test/java/org/springframework/repeat/exception/LogOrRethrowExceptionHandlerTests.java deleted file mode 100644 index 5d98969..0000000 --- a/src/test/java/org/springframework/repeat/exception/LogOrRethrowExceptionHandlerTests.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import java.io.StringWriter; - -import junit.framework.TestCase; - -import org.apache.log4j.Logger; -import org.apache.log4j.SimpleLayout; -import org.apache.log4j.WriterAppender; -import org.springframework.classify.ClassifierSupport; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.exception.LogOrRethrowExceptionHandler.Level; - -public class LogOrRethrowExceptionHandlerTests extends TestCase { - - private LogOrRethrowExceptionHandler handler = new LogOrRethrowExceptionHandler(); - - private StringWriter writer; - - private RepeatContext context = null; - - protected void setUp() throws Exception { - super.setUp(); - Logger logger = Logger.getLogger(LogOrRethrowExceptionHandler.class); - logger.setLevel(org.apache.log4j.Level.DEBUG); - writer = new StringWriter(); - logger.removeAllAppenders(); - logger.getParent().removeAllAppenders(); - logger.addAppender(new WriterAppender(new SimpleLayout(), writer)); - } - - public void testRuntimeException() throws Throwable { - try { - handler.handleException(context, new RuntimeException("Foo")); - fail("Expected RuntimeException"); - } - catch (RuntimeException e) { - assertEquals("Foo", e.getMessage()); - } - } - - public void testError() throws Throwable { - try { - handler.handleException(context, new Error("Foo")); - fail("Expected Error"); - } - catch (Error e) { - assertEquals("Foo", e.getMessage()); - } - } - - public void testNotRethrownErrorLevel() throws Throwable { - handler.setExceptionClassifier(new ClassifierSupport(Level.RETHROW) { - public Level classify(Throwable throwable) { - return Level.ERROR; - } - }); - // No exception... - handler.handleException(context, new Error("Foo")); - assertNotNull(writer.toString()); - } - - public void testNotRethrownWarnLevel() throws Throwable { - handler.setExceptionClassifier(new ClassifierSupport(Level.RETHROW) { - public Level classify(Throwable throwable) { - return Level.WARN; - } - }); - // No exception... - handler.handleException(context, new Error("Foo")); - assertNotNull(writer.toString()); - } - - public void testNotRethrownDebugLevel() throws Throwable { - handler.setExceptionClassifier(new ClassifierSupport(Level.RETHROW) { - public Level classify(Throwable throwable) { - return Level.DEBUG; - } - }); - // No exception... - handler.handleException(context, new Error("Foo")); - assertNotNull(writer.toString()); - } - -} diff --git a/src/test/java/org/springframework/repeat/exception/RethrowOnThresholdExceptionHandlerTests.java b/src/test/java/org/springframework/repeat/exception/RethrowOnThresholdExceptionHandlerTests.java deleted file mode 100644 index 0ab51c8..0000000 --- a/src/test/java/org/springframework/repeat/exception/RethrowOnThresholdExceptionHandlerTests.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -import java.util.Collections; -import java.util.concurrent.atomic.AtomicInteger; - -import org.junit.Test; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.context.RepeatContextSupport; - -public class RethrowOnThresholdExceptionHandlerTests { - - private RethrowOnThresholdExceptionHandler handler = new RethrowOnThresholdExceptionHandler(); - - private RepeatContext parent = new RepeatContextSupport(null); - - private RepeatContext context = new RepeatContextSupport(parent); - - @Test - public void testRuntimeException() throws Throwable { - try { - handler.handleException(context, new RuntimeException("Foo")); - fail("Expected RuntimeException"); - } - catch (RuntimeException e) { - assertEquals("Foo", e.getMessage()); - } - } - - @Test - public void testError() throws Throwable { - try { - handler.handleException(context, new Error("Foo")); - fail("Expected Error"); - } - catch (Error e) { - assertEquals("Foo", e.getMessage()); - } - } - - @Test - public void testNotRethrownWithThreshold() throws Throwable { - handler.setThresholds(Collections., Integer> singletonMap(Exception.class, 1)); - // No exception... - handler.handleException(context, new RuntimeException("Foo")); - AtomicInteger counter = (AtomicInteger) context.getAttribute(context.attributeNames()[0]); - assertNotNull(counter); - assertEquals(1, counter.get()); - } - - @Test - public void testRethrowOnThreshold() throws Throwable { - handler.setThresholds(Collections., Integer> singletonMap(Exception.class, 2)); - // No exception... - handler.handleException(context, new RuntimeException("Foo")); - handler.handleException(context, new RuntimeException("Foo")); - try { - handler.handleException(context, new RuntimeException("Foo")); - fail("Expected RuntimeException"); - } - catch (RuntimeException e) { - assertEquals("Foo", e.getMessage()); - } - } - - @Test - public void testNotUseParent() throws Throwable { - handler.setThresholds(Collections., Integer> singletonMap(Exception.class, 1)); - // No exception... - handler.handleException(context, new RuntimeException("Foo")); - context = new RepeatContextSupport(parent); - try { - // No exception again - context is changed... - handler.handleException(context, new RuntimeException("Foo")); - } - catch (RuntimeException e) { - fail("Unexpected Error"); - } - } - - @Test - public void testUseParent() throws Throwable { - handler.setThresholds(Collections., Integer> singletonMap(Exception.class, 1)); - handler.setUseParent(true); - // No exception... - handler.handleException(context, new RuntimeException("Foo")); - context = new RepeatContextSupport(parent); - try { - handler.handleException(context, new RuntimeException("Foo")); - fail("Expected Error"); - } - catch (RuntimeException e) { - assertEquals("Foo", e.getMessage()); - } - } - -} diff --git a/src/test/java/org/springframework/repeat/exception/SimpleLimitExceptionHandlerTests.java b/src/test/java/org/springframework/repeat/exception/SimpleLimitExceptionHandlerTests.java deleted file mode 100644 index 86bc3be..0000000 --- a/src/test/java/org/springframework/repeat/exception/SimpleLimitExceptionHandlerTests.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.exception; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.repeat.context.RepeatContextSupport; - -/** - * Unit tests for {@link SimpleLimitExceptionHandler} - * - * @author Robert Kasanicky - * @author Dave Syer - */ -public class SimpleLimitExceptionHandlerTests { - - // object under test - private SimpleLimitExceptionHandler handler = new SimpleLimitExceptionHandler(); - - @Before - public void initializeHandler() throws Exception { - handler.afterPropertiesSet(); - } - - @Test - public void testInitializeWithNullContext() throws Throwable { - try { - handler.handleException(null, new RuntimeException("foo")); - fail("Expected IllegalArgumentException"); - } - catch (IllegalArgumentException e) { - // expected - } - } - - @Test - public void testInitializeWithNullContextAndNullException() throws Throwable { - try { - handler.handleException(null, null); - } - catch (IllegalArgumentException e) { - // expected; - } - } - - @Test - public void testDefaultBehaviour() throws Throwable { - Throwable throwable = new RuntimeException("foo"); - try { - handler.handleException(new RepeatContextSupport(null), throwable); - fail("Exception was swallowed."); - } - catch (RuntimeException expected) { - assertTrue("Exception is rethrown, ignoring the exception limit", true); - assertSame(expected, throwable); - } - } - - /** - * Other than nominated exception type should be rethrown, ignoring the - * exception limit. - * - * @throws Exception - */ - @Test - public void testNormalExceptionThrown() throws Throwable { - Throwable throwable = new RuntimeException("foo"); - - final int MORE_THAN_ZERO = 1; - handler.setLimit(MORE_THAN_ZERO); - handler.setExceptionClasses(Collections.> singleton(IllegalArgumentException.class)); - handler.afterPropertiesSet(); - - try { - handler.handleException(new RepeatContextSupport(null), throwable); - fail("Exception was swallowed."); - } - catch (RuntimeException expected) { - assertTrue("Exception is rethrown, ignoring the exception limit", true); - assertSame(expected, throwable); - } - } - - /** - * TransactionInvalidException should only be rethrown below the exception - * limit. - * - * @throws Exception - */ - @Test - public void testLimitedExceptionTypeNotThrown() throws Throwable { - final int MORE_THAN_ZERO = 1; - handler.setLimit(MORE_THAN_ZERO); - handler.setExceptionClasses(Collections.> singleton(RuntimeException.class)); - handler.afterPropertiesSet(); - - try { - handler.handleException(new RepeatContextSupport(null), new RuntimeException("foo")); - } - catch (RuntimeException expected) { - fail("Unexpected exception."); - } - } - - /** - * TransactionInvalidException should only be rethrown below the exception - * limit. - * - * @throws Exception - */ - @Test - public void testLimitedExceptionNotThrownFromSiblings() throws Throwable { - Throwable throwable = new RuntimeException("foo"); - - final int MORE_THAN_ZERO = 1; - handler.setLimit(MORE_THAN_ZERO); - handler.setExceptionClasses(Collections.> singleton(RuntimeException.class)); - handler.afterPropertiesSet(); - - RepeatContextSupport parent = new RepeatContextSupport(null); - - try { - RepeatContextSupport context = new RepeatContextSupport(parent); - handler.handleException(context, throwable); - context = new RepeatContextSupport(parent); - handler.handleException(context, throwable); - } - catch (RuntimeException expected) { - fail("Unexpected exception."); - } - } - - /** - * TransactionInvalidException should only be rethrown below the exception - * limit. - * - * @throws Exception - */ - @Test - public void testLimitedExceptionThrownFromSiblingsWhenUsingParent() throws Throwable { - Throwable throwable = new RuntimeException("foo"); - - final int MORE_THAN_ZERO = 1; - handler.setLimit(MORE_THAN_ZERO); - handler.setExceptionClasses(Collections.> singleton(RuntimeException.class)); - handler.setUseParent(true); - handler.afterPropertiesSet(); - - RepeatContextSupport parent = new RepeatContextSupport(null); - - try { - RepeatContextSupport context = new RepeatContextSupport(parent); - handler.handleException(context, throwable); - context = new RepeatContextSupport(parent); - handler.handleException(context, throwable); - fail("Expected exception."); - } - catch (RuntimeException expected) { - assertSame(throwable, expected); - } - } - - /** - * Exceptions are swallowed until the exception limit is exceeded. After the - * limit is exceeded exceptions are rethrown - */ - @Test - public void testExceptionNotThrownBelowLimit() throws Throwable { - - final int EXCEPTION_LIMIT = 3; - handler.setLimit(EXCEPTION_LIMIT); - handler.afterPropertiesSet(); - - List throwables = new ArrayList() { - { - for (int i = 0; i < (EXCEPTION_LIMIT); i++) { - add(new RuntimeException("below exception limit")); - } - } - }; - - RepeatContextSupport context = new RepeatContextSupport(null); - - try { - for (Throwable throwable : throwables) { - - handler.handleException(context, throwable); - assertTrue("exceptions up to limit are swallowed", true); - - } - } - catch (RuntimeException unexpected) { - fail("exception rethrown although exception limit was not exceeded"); - } - - } - - /** - * TransactionInvalidExceptions are swallowed until the exception limit is - * exceeded. After the limit is exceeded exceptions are rethrown as - * BatchCriticalExceptions - */ - @Test - public void testExceptionThrownAboveLimit() throws Throwable { - - final int EXCEPTION_LIMIT = 3; - handler.setLimit(EXCEPTION_LIMIT); - handler.afterPropertiesSet(); - - List throwables = new ArrayList() { - { - for (int i = 0; i < (EXCEPTION_LIMIT); i++) { - add(new RuntimeException("below exception limit")); - } - } - }; - - throwables.add(new RuntimeException("above exception limit")); - - RepeatContextSupport context = new RepeatContextSupport(null); - - try { - for (Throwable throwable : throwables) { - - handler.handleException(context, throwable); - assertTrue("exceptions up to limit are swallowed", true); - - } - } - catch (RuntimeException expected) { - assertEquals("above exception limit", expected.getMessage()); - } - - // after reaching the limit, behaviour should be idempotent - try { - handler.handleException(context, new RuntimeException("foo")); - assertTrue("exceptions up to limit are swallowed", true); - - } - catch (RuntimeException expected) { - assertEquals("foo", expected.getMessage()); - } - } -} diff --git a/src/test/java/org/springframework/repeat/interceptor/RepeatOperationsInterceptorTests.java b/src/test/java/org/springframework/repeat/interceptor/RepeatOperationsInterceptorTests.java deleted file mode 100644 index 125ba55..0000000 --- a/src/test/java/org/springframework/repeat/interceptor/RepeatOperationsInterceptorTests.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.interceptor; - -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import junit.framework.TestCase; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.springframework.aop.framework.Advised; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatException; -import org.springframework.repeat.RepeatOperations; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.policy.SimpleCompletionPolicy; -import org.springframework.repeat.support.RepeatTemplate; - -public class RepeatOperationsInterceptorTests extends TestCase { - - private RepeatOperationsInterceptor interceptor; - - private Service service; - - private ServiceImpl target; - - protected void setUp() throws Exception { - super.setUp(); - interceptor = new RepeatOperationsInterceptor(); - target = new ServiceImpl(); - ProxyFactory factory = new ProxyFactory(RepeatOperations.class.getClassLoader()); - factory.setInterfaces(new Class[] { Service.class }); - factory.setTarget(target); - service = (Service) factory.getProxy(); - } - - public void testDefaultInterceptorSunnyDay() throws Exception { - ((Advised) service).addAdvice(interceptor); - service.service(); - assertEquals(3, target.count); - } - - public void testCompleteOnFirstInvocation() throws Exception { - ((Advised) service).addAdvice(interceptor); - target.setMaxService(0); - service.service(); - assertEquals(1, target.count); - } - - public void testSetTemplate() throws Exception { - final List calls = new ArrayList(); - interceptor.setRepeatOperations(new RepeatOperations() { - public RepeatStatus iterate(RepeatCallback callback) { - try { - Object result = callback.doInIteration(null); - calls.add(result); - } - catch (Exception e) { - throw new RepeatException("Encountered exception in repeat.", e); - } - return RepeatStatus.CONTINUABLE; - } - }); - ((Advised) service).addAdvice(interceptor); - service.service(); - assertEquals(1, calls.size()); - } - - public void testCallbackNotExecuted() throws Exception { - final List calls = new ArrayList(); - interceptor.setRepeatOperations(new RepeatOperations() { - public RepeatStatus iterate(RepeatCallback callback) { - calls.add(null); - return RepeatStatus.FINISHED; - } - }); - ((Advised) service).addAdvice(interceptor); - try { - service.service(); - fail("Expected IllegalStateException"); - } catch (IllegalStateException e) { - String message = e.getMessage(); - assertTrue("Wrong exception message: "+message, message.toLowerCase().indexOf("no result available")>=0); - } - assertEquals(1, calls.size()); - } - - public void testVoidServiceSunnyDay() throws Exception { - ((Advised) service).addAdvice(interceptor); - RepeatTemplate template = new RepeatTemplate(); - // N.B. the default completion policy results in an infinite loop, so we - // need to set the chunk size. - template.setCompletionPolicy(new SimpleCompletionPolicy(2)); - interceptor.setRepeatOperations(template); - service.alternate(); - assertEquals(2, target.count); - } - - public void testCallbackWithException() throws Exception { - ((Advised) service).addAdvice(interceptor); - try { - service.exception(); - fail("Expected RuntimeException"); - } - catch (RuntimeException e) { - assertEquals("Duh", e.getMessage().substring(0, 3)); - } - } - - public void testCallbackWithThrowable() throws Exception { - ((Advised) service).addAdvice(interceptor); - try { - service.error(); - fail("Expected Error"); - } - catch (Error e) { - assertEquals("Duh", e.getMessage().substring(0, 3)); - } - } - - public void testCallbackWithBoolean() throws Exception { - RepeatTemplate template = new RepeatTemplate(); - // N.B. the default completion policy results in an infinite loop, so we - // need to set the chunk size. - template.setCompletionPolicy(new SimpleCompletionPolicy(2)); - interceptor.setRepeatOperations(template); - ((Advised) service).addAdvice(interceptor); - assertTrue(service.isContinuable()); - assertEquals(2, target.count); - } - - public void testCallbackWithBooleanReturningFalseFirstTime() throws Exception { - target.setComplete(true); - ((Advised) service).addAdvice(interceptor); - // Complete without repeat when boolean return value is false - assertFalse(service.isContinuable()); - assertEquals(1, target.count); - } - - public void testInterceptorChainWithRetry() throws Exception { - ((Advised) service).addAdvice(interceptor); - final List list = new ArrayList(); - ((Advised) service).addAdvice(new MethodInterceptor() { - public Object invoke(MethodInvocation invocation) throws Throwable { - list.add("chain"); - return invocation.proceed(); - } - }); - RepeatTemplate template = new RepeatTemplate(); - template.setCompletionPolicy(new SimpleCompletionPolicy(2)); - interceptor.setRepeatOperations(template); - service.service(); - assertEquals(2, target.count); - assertEquals(2, list.size()); - } - - public void testIllegalMethodInvocationType() throws Throwable { - try { - interceptor.invoke(new MethodInvocation() { - public Method getMethod() { - try { - return Object.class.getMethod("toString", new Class[0]); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } - - public Object[] getArguments() { - return null; - } - - public AccessibleObject getStaticPart() { - return null; - } - - public Object getThis() { - return null; - } - - public Object proceed() throws Throwable { - return null; - } - }); - fail("IllegalStateException expected"); - } - catch (IllegalStateException e) { - assertTrue("Exception message should contain MethodInvocation: " + e.getMessage(), e.getMessage().indexOf( - "MethodInvocation") >= 0); - } - } - - private interface Service { - Object service() throws Exception; - - void alternate() throws Exception; - - Object exception() throws Exception; - - Object error() throws Exception; - - boolean isContinuable() throws Exception; - } - - private static class ServiceImpl implements Service { - private int count = 0; - - private boolean complete; - - private int maxService = 2; - - /** - * Public setter for the maximum number of times to call service(). - * @param maxService the maxService to set - */ - public void setMaxService(int maxService) { - this.maxService = maxService; - } - - public Object service() throws Exception { - count++; - if (count <= maxService) { - return Integer.valueOf(count); - } - else { - return null; - } - } - - public void setComplete(boolean complete) { - this.complete = complete; - } - - public void alternate() throws Exception { - count++; - } - - public Object exception() throws Exception { - throw new RuntimeException("Duh! Stupid."); - } - - public Object error() throws Exception { - throw new Error("Duh! Stupid error."); - } - - public boolean isContinuable() throws Exception { - count++; - return !complete; - } - } - -} diff --git a/src/test/java/org/springframework/repeat/listener/CompositeRepeatListenerTests.java b/src/test/java/org/springframework/repeat/listener/CompositeRepeatListenerTests.java deleted file mode 100644 index 430c34f..0000000 --- a/src/test/java/org/springframework/repeat/listener/CompositeRepeatListenerTests.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.repeat.listener; - -import java.util.ArrayList; -import java.util.List; - -import junit.framework.TestCase; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatListener; -import org.springframework.repeat.context.RepeatContextSupport; - -/** - * @author Dave Syer - * - */ -public class CompositeRepeatListenerTests extends TestCase { - - private CompositeRepeatListener listener = new CompositeRepeatListener(); - private RepeatContext context = new RepeatContextSupport(null); - - private List list = new ArrayList(); - - /** - * Test method for {@link CompositeRepeatListener#setListeners(RepeatListener[])}. - */ - public void testSetListeners() { - listener.setListeners(new RepeatListener[] { new RepeatListenerSupport() { - public void open(RepeatContext context) { - list.add("fail"); - } - }, new RepeatListenerSupport() { - public void open(RepeatContext context) { - list.add("continue"); - } - } }); - listener.open(context); - assertEquals(2, list.size()); - } - - /** - * Test method for - * {@link CompositeRepeatListener#register(RepeatListener)}. - */ - public void testSetListener() { - listener.register(new RepeatListenerSupport() { - public void before(RepeatContext context) { - list.add("fail"); - } - }); - listener.before(context); - assertEquals(1, list.size()); - } - - public void testClose() { - listener.register(new RepeatListenerSupport() { - public void close(RepeatContext context) { - list.add("foo"); - } - }); - listener.close(context); - assertEquals(1, list.size()); - } - - public void testOnError() { - listener.register(new RepeatListenerSupport() { - public void onError(RepeatContext context, Throwable e) { - list.add(e); - } - }); - listener.onError(context, new RuntimeException("foo")); - assertEquals(1, list.size()); - } - -} diff --git a/src/test/java/org/springframework/repeat/listener/RepeatListenerTests.java b/src/test/java/org/springframework/repeat/listener/RepeatListenerTests.java deleted file mode 100644 index fc5be09..0000000 --- a/src/test/java/org/springframework/repeat/listener/RepeatListenerTests.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.listener; - -import java.util.ArrayList; -import java.util.List; - -import junit.framework.TestCase; - -import org.springframework.core.task.SimpleAsyncTaskExecutor; -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatListener; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.support.RepeatTemplate; -import org.springframework.repeat.support.TaskExecutorRepeatTemplate; - -public class RepeatListenerTests extends TestCase { - - int count = 0; - - public void testBeforeInterceptors() throws Exception { - RepeatTemplate template = new RepeatTemplate(); - final List calls = new ArrayList(); - template.setListeners(new RepeatListener[] { new RepeatListenerSupport() { - public void before(RepeatContext context) { - calls.add("1"); - } - }, new RepeatListenerSupport() { - public void before(RepeatContext context) { - calls.add("2"); - } - } }); - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - count++; - return RepeatStatus.continueIf(count <= 1); - } - }); - // 2 calls: the second time there is no processing - // (despite the fact that the callback returned null and batch was - // complete). Is this OK? - assertEquals(2, count); - // ... but the interceptor before() was called: - assertEquals("[1, 2, 1, 2]", calls.toString()); - } - - public void testBeforeInterceptorCanVeto() throws Exception { - RepeatTemplate template = new RepeatTemplate(); - final List calls = new ArrayList(); - template.registerListener(new RepeatListenerSupport() { - public void before(RepeatContext context) { - calls.add("1"); - context.setCompleteOnly(); - } - }); - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - count++; - return RepeatStatus.FINISHED; - } - }); - assertEquals(0, count); - // ... but the interceptor before() was called: - assertEquals("[1]", calls.toString()); - } - - public void testAfterInterceptors() throws Exception { - RepeatTemplate template = new RepeatTemplate(); - final List calls = new ArrayList(); - template.setListeners(new RepeatListener[] { new RepeatListenerSupport() { - public void after(RepeatContext context, RepeatStatus result) { - calls.add("1"); - } - }, new RepeatListenerSupport() { - public void after(RepeatContext context, RepeatStatus result) { - calls.add("2"); - } - } }); - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - count++; - return RepeatStatus.continueIf(count <= 1); - } - }); - // 2 calls to the callback, and the second one had no processing... - assertEquals(2, count); - // ... so the interceptor after() is not called: - assertEquals("[2, 1]", calls.toString()); - } - - public void testOpenInterceptors() throws Exception { - RepeatTemplate template = new RepeatTemplate(); - final List calls = new ArrayList(); - template.setListeners(new RepeatListener[] { new RepeatListenerSupport() { - public void open(RepeatContext context) { - calls.add("1"); - } - }, new RepeatListenerSupport() { - public void open(RepeatContext context) { - calls.add("2"); - context.setCompleteOnly(); - } - } }); - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - count++; - return RepeatStatus.CONTINUABLE; - } - }); - assertEquals(0, count); - assertEquals("[1, 2]", calls.toString()); - } - - public void testSingleOpenInterceptor() throws Exception { - RepeatTemplate template = new RepeatTemplate(); - final List calls = new ArrayList(); - template.registerListener(new RepeatListenerSupport() { - public void open(RepeatContext context) { - calls.add("1"); - } - }); - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - count++; - context.setCompleteOnly(); - return RepeatStatus.FINISHED; - } - }); - assertEquals(1, count); - assertEquals("[1]", calls.toString()); - } - - public void testCloseInterceptors() throws Exception { - RepeatTemplate template = new RepeatTemplate(); - final List calls = new ArrayList(); - template.setListeners(new RepeatListener[] { new RepeatListenerSupport() { - public void close(RepeatContext context) { - calls.add("1"); - } - }, new RepeatListenerSupport() { - public void close(RepeatContext context) { - calls.add("2"); - } - } }); - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - count++; - return RepeatStatus.continueIf(count < 2); - } - }); - // Test that more than one call comes in to the callback... - assertEquals(2, count); - // ... but the interceptor is only called once. - assertEquals("[2, 1]", calls.toString()); - } - - - public void testOnErrorInterceptors() throws Exception { - RepeatTemplate template = new RepeatTemplate(); - final List calls = new ArrayList(); - template.setListeners(new RepeatListener[] { new RepeatListenerSupport() { - public void onError(RepeatContext context, Throwable t) { - calls.add("1"); - } - }, new RepeatListenerSupport() { - public void onError(RepeatContext context, Throwable t) { - calls.add("2"); - } - } }); - try { - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - throw new IllegalStateException("Bogus"); - } - }); - fail("Expected IllegalStateException"); - } - catch (IllegalStateException e) { - // expected - } - assertEquals(0, count); - assertEquals("[2, 1]", calls.toString()); - } - - public void testOnErrorInterceptorsPrecedence() throws Exception { - RepeatTemplate template = new RepeatTemplate(); - final List calls = new ArrayList(); - template.setListeners(new RepeatListener[] { new RepeatListenerSupport() { - public void after(RepeatContext context, RepeatStatus result) { - calls.add("1"); - } - }, new RepeatListenerSupport() { - public void onError(RepeatContext context, Throwable t) { - calls.add("2"); - } - } }); - try { - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - throw new IllegalStateException("Bogus"); - } - }); - fail("Expected IllegalStateException"); - } - catch (IllegalStateException e) { - // expected - } - assertEquals(0, count); - // The after is not executed, if there is an error... - assertEquals("[2]", calls.toString()); - } - - public void testAsynchronousOnErrorInterceptorsPrecedence() throws Exception { - TaskExecutorRepeatTemplate template = new TaskExecutorRepeatTemplate(); - template.setTaskExecutor(new SimpleAsyncTaskExecutor()); - final List calls = new ArrayList(); - final List fails = new ArrayList(); - template.setListeners(new RepeatListener[] { new RepeatListenerSupport() { - public void after(RepeatContext context, RepeatStatus result) { - calls.add("1"); - } - }, new RepeatListenerSupport() { - public void onError(RepeatContext context, Throwable t) { - calls.add("2"); - fails.add("2"); - } - } }); - try { - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - throw new IllegalStateException("Bogus"); - } - }); - fail("Expected IllegalStateException"); - } - catch (IllegalStateException e) { - // expected - assertEquals("Bogus", e.getMessage()); - } - assertEquals(0, count); - System.err.println(calls); - // The after is not executed on error... - assertEquals("2", calls.get(0)); - assertEquals("2", calls.get(calls.size()-1)); - assertFalse(calls.contains("1")); - assertEquals(fails.size(), calls.size()); - } -} diff --git a/src/test/java/org/springframework/repeat/policy/CompositeCompletionPolicyTests.java b/src/test/java/org/springframework/repeat/policy/CompositeCompletionPolicyTests.java deleted file mode 100644 index 07fd6bf..0000000 --- a/src/test/java/org/springframework/repeat/policy/CompositeCompletionPolicyTests.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import junit.framework.TestCase; - -import org.springframework.repeat.CompletionPolicy; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; - -public class CompositeCompletionPolicyTests extends TestCase { - - public void testEmptyPolicies() throws Exception { - CompositeCompletionPolicy policy = new CompositeCompletionPolicy(); - RepeatContext context = policy.start(null); - assertNotNull(context); - assertFalse(policy.isComplete(context)); - } - - public void testTrivialPolicies() throws Exception { - CompositeCompletionPolicy policy = new CompositeCompletionPolicy(); - policy.setPolicies(new CompletionPolicy[] { new MockCompletionPolicySupport(), - new MockCompletionPolicySupport() }); - RepeatContext context = policy.start(null); - assertEquals(0, context.getStartedCount()); - assertFalse(policy.isComplete(context)); - assertFalse(policy.isComplete(context, null)); - policy.update(context); - assertEquals(1, context.getStartedCount()); - } - - public void testNonTrivialPolicies() throws Exception { - CompositeCompletionPolicy policy = new CompositeCompletionPolicy(); - policy.setPolicies(new CompletionPolicy[] { new MockCompletionPolicySupport(), - new MockCompletionPolicySupport() { - public boolean isComplete(RepeatContext context) { - return true; - } - } }); - RepeatContext context = policy.start(null); - assertTrue(policy.isComplete(context)); - } - - public void testNonTrivialPoliciesWithResult() throws Exception { - CompositeCompletionPolicy policy = new CompositeCompletionPolicy(); - policy.setPolicies(new CompletionPolicy[] { new MockCompletionPolicySupport(), - new MockCompletionPolicySupport() { - public boolean isComplete(RepeatContext context, RepeatStatus result) { - return true; - } - } }); - RepeatContext context = policy.start(null); - assertTrue(policy.isComplete(context, null)); - } -} diff --git a/src/test/java/org/springframework/repeat/policy/CountingCompletionPolicyTests.java b/src/test/java/org/springframework/repeat/policy/CountingCompletionPolicyTests.java deleted file mode 100644 index 65a1c29..0000000 --- a/src/test/java/org/springframework/repeat/policy/CountingCompletionPolicyTests.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import junit.framework.TestCase; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.context.RepeatContextSupport; - -public class CountingCompletionPolicyTests extends TestCase { - - public void testDefaultBehaviour() throws Exception { - CountingCompletionPolicy policy = new CountingCompletionPolicy() { - protected int getCount(RepeatContext context) { - return 1; - }; - }; - RepeatContext context = policy.start(null); - assertTrue(policy.isComplete(context)); - } - - public void testNullResult() throws Exception { - CountingCompletionPolicy policy = new CountingCompletionPolicy() { - protected int getCount(RepeatContext context) { - return 1; - }; - }; - policy.setMaxCount(10); - RepeatContext context = policy.start(null); - assertTrue(policy.isComplete(context, null)); - } - - public void testFinishedResult() throws Exception { - CountingCompletionPolicy policy = new CountingCompletionPolicy() { - protected int getCount(RepeatContext context) { - return 1; - }; - }; - policy.setMaxCount(10); - RepeatContext context = policy.start(null); - assertTrue(policy.isComplete(context, RepeatStatus.FINISHED)); - } - - public void testDefaultBehaviourWithUpdate() throws Exception { - CountingCompletionPolicy policy = new CountingCompletionPolicy() { - int count = 0; - - protected int getCount(RepeatContext context) { - return count; - }; - - protected int doUpdate(RepeatContext context) { - count++; - return 1; - } - }; - policy.setMaxCount(2); - RepeatContext context = policy.start(null); - policy.update(context); - assertFalse(policy.isComplete(context)); - policy.update(context); - assertTrue(policy.isComplete(context)); - } - - public void testUpdateNotSavedAcrossSession() throws Exception { - CountingCompletionPolicy policy = new CountingCompletionPolicy() { - int count = 0; - - protected int getCount(RepeatContext context) { - return count; - }; - - protected int doUpdate(RepeatContext context) { - super.doUpdate(context); - count++; - return 1; - } - - public RepeatContext start(RepeatContext context) { - count = 0; - return super.start(context); - } - }; - policy.setMaxCount(2); - RepeatContextSupport session = new RepeatContextSupport(null); - RepeatContext context = policy.start(session); - policy.update(context); - assertFalse(policy.isComplete(context)); - context = policy.start(session); - policy.update(context); - assertFalse(policy.isComplete(context)); - } - - public void testUpdateSavedAcrossSession() throws Exception { - CountingCompletionPolicy policy = new CountingCompletionPolicy() { - int count = 0; - - protected int getCount(RepeatContext context) { - return count; - }; - - protected int doUpdate(RepeatContext context) { - super.doUpdate(context); - count++; - return 1; - } - - public RepeatContext start(RepeatContext context) { - count = 0; - return super.start(context); - } - }; - policy.setMaxCount(2); - policy.setUseParent(true); - RepeatContextSupport session = new RepeatContextSupport(null); - RepeatContext context = policy.start(session); - policy.update(context); - assertFalse(policy.isComplete(context)); - context = policy.start(session); - policy.update(context); - assertTrue(policy.isComplete(context)); - } -} diff --git a/src/test/java/org/springframework/repeat/policy/MockCompletionPolicySupport.java b/src/test/java/org/springframework/repeat/policy/MockCompletionPolicySupport.java deleted file mode 100644 index 359a548..0000000 --- a/src/test/java/org/springframework/repeat/policy/MockCompletionPolicySupport.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import org.springframework.repeat.RepeatContext; - -public class MockCompletionPolicySupport extends CompletionPolicySupport { - - public boolean isComplete(RepeatContext context) { - return false; - } - -} diff --git a/src/test/java/org/springframework/repeat/policy/SimpleCompletionPolicyTests.java b/src/test/java/org/springframework/repeat/policy/SimpleCompletionPolicyTests.java deleted file mode 100644 index db9e1a1..0000000 --- a/src/test/java/org/springframework/repeat/policy/SimpleCompletionPolicyTests.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import junit.framework.TestCase; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; - -public class SimpleCompletionPolicyTests extends TestCase { - - SimpleCompletionPolicy policy = new SimpleCompletionPolicy(); - - RepeatContext context; - - RepeatStatus dummy = RepeatStatus.CONTINUABLE; - - protected void setUp() throws Exception { - super.setUp(); - context = policy.start(null); - } - - public void testTerminationAfterDefaultSize() throws Exception { - for (int i = 0; i < SimpleCompletionPolicy.DEFAULT_CHUNK_SIZE - 1; i++) { - policy.update(context); - assertFalse(policy.isComplete(context, dummy)); - } - policy.update(context); - assertTrue(policy.isComplete(context, dummy)); - } - - public void testTerminationAfterExplicitChunkSize() throws Exception { - int chunkSize = 2; - policy.setChunkSize(chunkSize); - for (int i = 0; i < chunkSize - 1; i++) { - policy.update(context); - assertFalse(policy.isComplete(context, dummy)); - } - policy.update(context); - assertTrue(policy.isComplete(context, dummy)); - } - - public void testTerminationAfterNullResult() throws Exception { - policy.update(context); - assertFalse(policy.isComplete(context, dummy)); - policy.update(context); - assertTrue(policy.isComplete(context, null)); - } - - public void testReset() throws Exception { - policy.setChunkSize(2); - policy.update(context); - assertFalse(policy.isComplete(context, dummy)); - policy.update(context); - assertTrue(policy.isComplete(context, dummy)); - context = policy.start(null); - policy.update(context); - assertFalse(policy.isComplete(context, dummy)); - } -} diff --git a/src/test/java/org/springframework/repeat/policy/TimeoutCompletionPolicyTests.java b/src/test/java/org/springframework/repeat/policy/TimeoutCompletionPolicyTests.java deleted file mode 100644 index f4903b7..0000000 --- a/src/test/java/org/springframework/repeat/policy/TimeoutCompletionPolicyTests.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.policy; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; - -public class TimeoutCompletionPolicyTests { - - @Test - public void testSimpleTimeout() throws Exception { - TimeoutTerminationPolicy policy = new TimeoutTerminationPolicy(20L); - RepeatContext context = policy.start(null); - assertFalse(policy.isComplete(context)); - Thread.sleep(50L); - assertTrue(policy.isComplete(context)); - } - - @Test - public void testSuccessfulResult() throws Exception { - TimeoutTerminationPolicy policy = new TimeoutTerminationPolicy(); - RepeatContext context = policy.start(null); - assertFalse(policy.isComplete(context, null)); - } - - @Test - public void testNonContinuableResult() throws Exception { - TimeoutTerminationPolicy policy = new TimeoutTerminationPolicy(); - RepeatStatus result = RepeatStatus.FINISHED; - assertTrue(policy.isComplete(policy.start(null), result)); - } - - @Test - public void testUpdate() throws Exception { - TimeoutTerminationPolicy policy = new TimeoutTerminationPolicy(20L); - RepeatContext context = policy.start(null); - assertFalse(policy.isComplete(context)); - Thread.sleep(50L); - assertTrue(policy.isComplete(context)); - policy.update(context); - // update doesn't change completeness - assertTrue(policy.isComplete(context)); - } - -} diff --git a/src/test/java/org/springframework/repeat/support/AbstractTradeBatchTests.java b/src/test/java/org/springframework/repeat/support/AbstractTradeBatchTests.java deleted file mode 100644 index 7295200..0000000 --- a/src/test/java/org/springframework/repeat/support/AbstractTradeBatchTests.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import java.util.List; - -import org.junit.Before; - -/** - * Base class for simple tests with small trade data set. - * - * @author Dave Syer - * - */ -public abstract class AbstractTradeBatchTests { - - public static final int NUMBER_OF_ITEMS = 5; - - protected TradeWriter processor = new TradeWriter(); - - protected TradeReader provider; - - @Before - public void setUp() throws Exception { - provider = new TradeReader(); - } - - protected static class TradeReader { - - private Trade[] trades = new Trade[] { - new Trade("UK21341EAH45", 978, "98.34"), - new Trade("UK21341EAH46", 112, "18.12"), - new Trade("UK21341EAH47", 245, "12.78"), - new Trade("UK21341EAH48", 108, "109.25"), - new Trade("UK21341EAH49", 854, "123.39") }; - - private int count = 0; - - public Trade read() { - if (count < trades.length) { - return trades[count++]; - } - return null; - } - - } - - protected static class TradeWriter { - int count = 0; - - // This has to be synchronized because we are going to test the state - // (count) at the end of a concurrent batch run. - public synchronized void write(List data) { - count++; - System.out.println("Executing trade '" + data + "'"); - } - } - -} diff --git a/src/test/java/org/springframework/repeat/support/ChunkedRepeatTests.java b/src/test/java/org/springframework/repeat/support/ChunkedRepeatTests.java deleted file mode 100644 index b7d1832..0000000 --- a/src/test/java/org/springframework/repeat/support/ChunkedRepeatTests.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.Arrays; - -import org.junit.Test; -import org.springframework.core.task.SimpleAsyncTaskExecutor; -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.callback.NestedRepeatCallback; -import org.springframework.repeat.policy.SimpleCompletionPolicy; - -/** - * Test various approaches to chunking of a batch. Not really a unit test, but - * it should be fast. - * - * @author Dave Syer - * - */ -public class ChunkedRepeatTests extends AbstractTradeBatchTests { - - private int count = 0; - - public static class TradeRepeatCallback implements RepeatCallback { - - private final TradeReader provider; - private final TradeWriter processor; - - public TradeRepeatCallback(TradeReader provider, TradeWriter processor) { - this.provider = provider; - this.processor = processor; - - } - - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - Trade item = provider.read(); - if (item == null) { - return RepeatStatus.FINISHED; - } - processor.write(Arrays.asList(item)); - return RepeatStatus.CONTINUABLE; - } - } - - - /** - * Chunking using a dedicated TerminationPolicy. Transactions would be laid - * on at the level of chunkTemplate.execute() or the surrounding callback. - * - * @throws Exception - */ - @Test - public void testChunkedBatchWithTerminationPolicy() throws Exception { - - RepeatTemplate repeatTemplate = new RepeatTemplate(); - final RepeatCallback callback = new TradeRepeatCallback(provider, processor); - - final RepeatTemplate chunkTemplate = new RepeatTemplate(); - // The policy is resettable so we only have to resolve this dependency - // once - chunkTemplate.setCompletionPolicy(new SimpleCompletionPolicy(2)); - - RepeatStatus result = repeatTemplate.iterate(new NestedRepeatCallback(chunkTemplate, callback) { - - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - count++; // for test assertion - return super.doInIteration(context); - } - - }); - - assertEquals(NUMBER_OF_ITEMS, processor.count); - // The chunk executes 3 times because the last one - // returns false. We terminate the main batch when - // we encounter a partially empty chunk. - assertEquals(3, count); - assertFalse(result.isContinuable()); - - } - - /** - * Chunking with an asynchronous taskExecutor in the chunks. Transactions - * have to be at the level of the business callback. - * - * @throws Exception - */ - @Test - public void testAsynchronousChunkedBatchWithCompletionPolicy() throws Exception { - - RepeatTemplate repeatTemplate = new RepeatTemplate(); - final RepeatCallback callback = new TradeRepeatCallback(provider, processor); - - final TaskExecutorRepeatTemplate chunkTemplate = new TaskExecutorRepeatTemplate(); - // The policy is resettable so we only have to resolve this dependency - // once - chunkTemplate.setCompletionPolicy(new SimpleCompletionPolicy(2)); - chunkTemplate.setTaskExecutor(new SimpleAsyncTaskExecutor()); - - RepeatStatus result = repeatTemplate.iterate(new NestedRepeatCallback(chunkTemplate, callback) { - - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - count++; // for test assertion - return super.doInIteration(context); - } - - }); - - assertEquals(NUMBER_OF_ITEMS, processor.count); - assertFalse(result.isContinuable()); - assertTrue("Expected at least 3 chunks but found: "+count, count>=3); - - } - - /** - * Explicit chunking of input data. Transactions would be laid on at the - * level of template.execute(). - * - * @throws Exception - */ - @Test - public void testChunksWithTruncatedItemProvider() throws Exception { - - RepeatTemplate template = new RepeatTemplate(); - - // This pattern would work with an asynchronous callback as well - // (but non-transactional in that case). - - class Chunker { - boolean ready = false; - - int count = 0; - - void set() { - ready = true; - } - - boolean ready() { - return ready; - } - - boolean first() { - return count == 0; - } - - void reset() { - count = 0; - ready = false; - } - - void increment() { - count++; - } - } - ; - - final Chunker chunker = new Chunker(); - - while (!chunker.ready()) { - - TradeReader truncated = new TradeReader() { - int count = 0; - - public Trade read() { - if (count++ < 2) - return provider.read(); - return null; - } - }; - chunker.reset(); - template.iterate(new TradeRepeatCallback(truncated, processor) { - - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - RepeatStatus result = super.doInIteration(context); - if (!result.isContinuable() && chunker.first()) { - chunker.set(); - } - chunker.increment(); - return result; - } - - }); - - } - - assertEquals(NUMBER_OF_ITEMS, processor.count); - - } - -} diff --git a/src/test/java/org/springframework/repeat/support/RepeatSynchronizationManagerTests.java b/src/test/java/org/springframework/repeat/support/RepeatSynchronizationManagerTests.java deleted file mode 100644 index 7845135..0000000 --- a/src/test/java/org/springframework/repeat/support/RepeatSynchronizationManagerTests.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import junit.framework.TestCase; - -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.context.RepeatContextSupport; - -public class RepeatSynchronizationManagerTests extends TestCase { - - private RepeatContext context = new RepeatContextSupport(null); - - protected void setUp() throws Exception { - RepeatSynchronizationManager.clear(); - } - - protected void tearDown() throws Exception { - RepeatSynchronizationManager.clear(); - } - - public void testGetContext() { - RepeatSynchronizationManager.register(context); - assertEquals(context, RepeatSynchronizationManager.getContext()); - } - - public void testSetSessionCompleteOnly() { - assertNull(RepeatSynchronizationManager.getContext()); - RepeatSynchronizationManager.register(context); - assertFalse(RepeatSynchronizationManager.getContext().isCompleteOnly()); - RepeatSynchronizationManager.setCompleteOnly(); - assertTrue(RepeatSynchronizationManager.getContext().isCompleteOnly()); - } - - public void testSetSessionCompleteOnlyWithParent() { - assertNull(RepeatSynchronizationManager.getContext()); - RepeatContext child = new RepeatContextSupport(context); - RepeatSynchronizationManager.register(child); - assertFalse(child.isCompleteOnly()); - RepeatSynchronizationManager.setAncestorsCompleteOnly(); - assertTrue(child.isCompleteOnly()); - assertTrue(context.isCompleteOnly()); - } - - public void testClear() { - RepeatSynchronizationManager.register(context); - assertEquals(context, RepeatSynchronizationManager.getContext()); - RepeatSynchronizationManager.clear(); - assertEquals(null, RepeatSynchronizationManager.getContext()); - } - -} diff --git a/src/test/java/org/springframework/repeat/support/ResultHolderResultQueueTests.java b/src/test/java/org/springframework/repeat/support/ResultHolderResultQueueTests.java deleted file mode 100644 index c573ca6..0000000 --- a/src/test/java/org/springframework/repeat/support/ResultHolderResultQueueTests.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.springframework.repeat.support; - - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; - -public class ResultHolderResultQueueTests { - - private ResultHolderResultQueue queue = new ResultHolderResultQueue(10); - - @Test - public void testPutTake() throws Exception { - queue.expect(); - assertTrue(queue.isExpecting()); - assertTrue(queue.isEmpty()); - queue.put(new TestResultHolder(RepeatStatus.CONTINUABLE)); - assertFalse(queue.isEmpty()); - assertTrue(queue.take().getResult().isContinuable()); - assertFalse(queue.isExpecting()); - } - - @Test - public void testOrdering() throws Exception { - queue.expect(); - queue.expect(); - queue.put(new TestResultHolder(RepeatStatus.FINISHED)); - queue.put(new TestResultHolder(RepeatStatus.CONTINUABLE)); - assertFalse(queue.isEmpty()); - assertTrue(queue.take().getResult().isContinuable()); - assertFalse(queue.take().getResult().isContinuable()); - } - - private static class TestResultHolder implements ResultHolder { - - private RepeatStatus result; - - private Throwable error; - - public TestResultHolder(RepeatStatus result) { - super(); - this.result = result; - } - - public RepeatContext getContext() { - return null; - } - - public Throwable getError() { - return error; - } - - public RepeatStatus getResult() { - return result; - } - } - -} diff --git a/src/test/java/org/springframework/repeat/support/SimpleRepeatTemplateTests.java b/src/test/java/org/springframework/repeat/support/SimpleRepeatTemplateTests.java deleted file mode 100644 index 1d90d68..0000000 --- a/src/test/java/org/springframework/repeat/support/SimpleRepeatTemplateTests.java +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.junit.Test; -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatException; -import org.springframework.repeat.RepeatListener; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.callback.NestedRepeatCallback; -import org.springframework.repeat.context.RepeatContextSupport; -import org.springframework.repeat.exception.ExceptionHandler; -import org.springframework.repeat.listener.RepeatListenerSupport; -import org.springframework.repeat.policy.CompletionPolicySupport; -import org.springframework.repeat.policy.SimpleCompletionPolicy; - -/** - * @author Dave Syer - */ -public class SimpleRepeatTemplateTests extends AbstractTradeBatchTests { - - private RepeatTemplate template = getRepeatTemplate(); - - private int count = 0; - - public static class TradeRepeatCallback implements RepeatCallback { - - private final TradeReader provider; - private final TradeWriter processor; - - public TradeRepeatCallback(TradeReader provider, TradeWriter processor) { - this.provider = provider; - this.processor = processor; - - } - - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - Trade item = provider.read(); - if (item == null) { - return RepeatStatus.FINISHED; - } - processor.write(Arrays.asList(item)); - return RepeatStatus.CONTINUABLE; - } - } - - public RepeatTemplate getRepeatTemplate() { - template = new RepeatTemplate(); - // default stop after more items than exist in dataset - template.setCompletionPolicy(new SimpleCompletionPolicy(8)); - return template; - } - - @Test - public void testExecute() throws Exception { - template.iterate(new TradeRepeatCallback(provider, processor)); - assertEquals(NUMBER_OF_ITEMS, processor.count); - } - - /** - * Check that a dedicated TerminationPolicy can terminate the batch. - * - * @throws Exception - */ - @Test - public void testEarlyCompletionWithPolicy() throws Exception { - - template.setCompletionPolicy(new SimpleCompletionPolicy(2)); - - template.iterate(new TradeRepeatCallback(provider, processor)); - - assertEquals(2, processor.count); - - } - - /** - * Check that a dedicated TerminationPolicy can terminate the batch. - * - * @throws Exception - */ - @Test - public void testEarlyCompletionWithException() throws Exception { - - try { - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - throw new IllegalStateException("foo!"); - } - }); - fail("Expected IllegalStateException"); - } catch (IllegalStateException e) { - assertEquals("foo!", e.getMessage()); - } - - assertEquals(1, count); - assertTrue("Too many attempts: " + count, count <= 10); - - } - - /** - * Check that the context is closed. - * - * @throws Exception - */ - @Test - public void testContextClosedOnNormalCompletion() throws Exception { - - final List list = new ArrayList(); - - final RepeatContext context = new RepeatContextSupport(null) { - public void close() { - super.close(); - list.add("close"); - } - }; - template.setCompletionPolicy(new CompletionPolicySupport() { - public RepeatContext start(RepeatContext c) { - return context; - } - }); - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - return RepeatStatus.continueIf(count < 1); - } - }); - - assertEquals(1, count); - assertEquals(1, list.size()); - - } - - /** - * Check that the context is closed. - * - * @throws Exception - */ - @Test - public void testContextClosedOnAbnormalCompletion() throws Exception { - - final List list = new ArrayList(); - - final RepeatContext context = new RepeatContextSupport(null) { - public void close() { - super.close(); - list.add("close"); - } - }; - template.setCompletionPolicy(new CompletionPolicySupport() { - public RepeatContext start(RepeatContext c) { - return context; - } - }); - - try { - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - throw new RuntimeException("foo"); - } - }); - } catch (RuntimeException e) { - assertEquals("foo", e.getMessage()); - } - - assertEquals(1, count); - assertEquals(1, list.size()); - - } - - /** - * Check that the exception handler is called. - * - * @throws Exception - */ - @Test - public void testExceptionHandlerCalledOnAbnormalCompletion() - throws Exception { - - final List list = new ArrayList(); - - template.setExceptionHandler(new ExceptionHandler() { - public void handleException(RepeatContext context, - Throwable throwable) throws RuntimeException { - list.add(throwable); - throw (RuntimeException) throwable; - } - }); - - try { - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - throw new RuntimeException("foo"); - } - }); - } catch (RuntimeException e) { - assertEquals("foo", e.getMessage()); - } - - assertEquals(1, count); - assertEquals(1, list.size()); - - } - - /** - * Check that a the context can be used to signal early completion. - * - * @throws Exception - */ - @Test - public void testEarlyCompletionWithContext() throws Exception { - - RepeatStatus result = template.iterate(new TradeRepeatCallback( - provider, processor) { - - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - RepeatStatus result = super.doInIteration(context); - if (processor.count >= 2) { - context.setCompleteOnly(); - // If we return null the batch will terminate anyway - // without an exception... - } - return result; - } - }); - - // 2 items were processed before completion signalled - assertEquals(2, processor.count); - - // Not all items processed - assertTrue(result.isContinuable()); - - } - - /** - * Check that a the context can be used to signal early completion. - * - * @throws Exception - */ - @Test - public void testEarlyCompletionWithContextTerminated() throws Exception { - - RepeatStatus result = template.iterate(new TradeRepeatCallback( - provider, processor) { - - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - RepeatStatus result = super.doInIteration(context); - if (processor.count >= 2) { - context.setTerminateOnly(); - // If we return null the batch will terminate anyway - // without an exception... - } - return result; - } - }); - - // 2 items were processed before completion signalled - assertEquals(2, processor.count); - - // Not all items processed - assertTrue(result.isContinuable()); - - } - - @Test - public void testNestedSession() throws Exception { - RepeatTemplate outer = getRepeatTemplate(); - RepeatTemplate inner = getRepeatTemplate(); - outer.iterate(new NestedRepeatCallback(inner, new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - assertNotNull(context); - assertNotSame("Nested batch should have new session", context, - context.getParent()); - assertSame(context, RepeatSynchronizationManager.getContext()); - return RepeatStatus.FINISHED; - } - }) { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - assertSame(context, RepeatSynchronizationManager.getContext()); - return super.doInIteration(context); - } - }); - assertEquals(2, count); - } - - @Test - public void testNestedSessionTerminatesBeforeIteration() throws Exception { - RepeatTemplate outer = getRepeatTemplate(); - RepeatTemplate inner = getRepeatTemplate(); - outer.iterate(new NestedRepeatCallback(inner, new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - assertEquals(2, count); - fail("Nested batch should not have been executed"); - return RepeatStatus.FINISHED; - } - }) { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - context.setCompleteOnly(); - return super.doInIteration(context); - } - }); - assertEquals(1, count); - } - - @Test - public void testOuterContextPreserved() throws Exception { - RepeatTemplate outer = getRepeatTemplate(); - outer.setCompletionPolicy(new SimpleCompletionPolicy(2)); - RepeatTemplate inner = getRepeatTemplate(); - outer.iterate(new NestedRepeatCallback(inner, new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - assertNotNull(context); - assertNotSame("Nested batch should have new session", context, - context.getParent()); - assertSame(context, RepeatSynchronizationManager.getContext()); - return RepeatStatus.FINISHED; - } - }) { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - assertSame(context, RepeatSynchronizationManager.getContext()); - super.doInIteration(context); - return RepeatStatus.CONTINUABLE; - } - }); - assertEquals(4, count); - } - - /** - * Test that a result is returned from the batch. - * - * @throws Exception - */ - @Test - public void testResult() throws Exception { - RepeatStatus result = template.iterate(new TradeRepeatCallback( - provider, processor)); - assertEquals(NUMBER_OF_ITEMS, processor.count); - // We are complete - do not expect to be called again - assertFalse(result.isContinuable()); - } - - @Test - public void testExceptionThrownOnLastItem() throws Exception { - template.setCompletionPolicy(new SimpleCompletionPolicy(2)); - try { - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - if (count < 2) { - return RepeatStatus.CONTINUABLE; - } - throw new RuntimeException("Barf second try count=" + count); - } - }); - fail("Expected exception on last item in batch"); - } catch (Exception e) { - // expected - assertEquals("Barf second try count=2", e.getMessage()); - } - } - - /** - * Check that a the session can be used to signal early completion, but an - * exception takes precedence. - * - * @throws Exception - */ - @Test - public void testEarlyCompletionWithSessionAndException() throws Exception { - - template.setCompletionPolicy(new SimpleCompletionPolicy(4)); - - RepeatStatus result = RepeatStatus.FINISHED; - - try { - result = template.iterate(new TradeRepeatCallback(provider, - processor) { - - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - RepeatStatus result = super.doInIteration(context); - if (processor.count >= 2) { - context.setCompleteOnly(); - throw new RuntimeException("Barf second try count=" - + processor.count); - } - return result; - } - }); - fail("Expected exception on last item in batch"); - } catch (RuntimeException e) { - // expected - assertEquals("Barf second try count=2", e.getMessage()); - } - - // 2 items were processed before completion signalled - assertEquals(2, processor.count); - - System.err.println(result); - - // An exception was thrown by the template so result is still false - assertFalse(result.isContinuable()); - - } - - /** - * Checked exceptions are wrapped into runtime RepeatException. - * RepeatException should be unwrapped before before it is passed to - * listeners and exception handler. - */ - @Test - public void testExceptionUnwrapping() { - - class TestException extends Exception { - TestException(String msg) { - super(msg); - } - } - final TestException exception = new TestException("CRASH!"); - - class ExceptionHandlerStub implements ExceptionHandler { - boolean called = false; - - public void handleException(RepeatContext context, - Throwable throwable) throws Throwable { - called = true; - assertSame(exception, throwable); - throw throwable; // re-throw so that repeat template - // terminates iteration - } - } - ExceptionHandlerStub exHandler = new ExceptionHandlerStub(); - - class RepeatListenerStub extends RepeatListenerSupport { - boolean called = false; - - public void onError(RepeatContext context, Throwable throwable) { - called = true; - assertSame(exception, throwable); - } - } - RepeatListenerStub listener = new RepeatListenerStub(); - - template.setExceptionHandler(exHandler); - template.setListeners(new RepeatListener[] { listener }); - - try { - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - throw new RepeatException( - "typically thrown by nested repeat template", - exception); - } - }); - fail(); - } catch (RepeatException expected) { - assertSame(exception, expected.getCause()); - } - - assertTrue(listener.called); - assertTrue(exHandler.called); - - } -} diff --git a/src/test/java/org/springframework/repeat/support/TaskExecutorRepeatTemplateAsynchronousTests.java b/src/test/java/org/springframework/repeat/support/TaskExecutorRepeatTemplateAsynchronousTests.java deleted file mode 100644 index e010269..0000000 --- a/src/test/java/org/springframework/repeat/support/TaskExecutorRepeatTemplateAsynchronousTests.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.junit.Test; -import org.springframework.core.task.SimpleAsyncTaskExecutor; -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.callback.NestedRepeatCallback; -import org.springframework.repeat.exception.ExceptionHandler; -import org.springframework.repeat.policy.SimpleCompletionPolicy; - -public class TaskExecutorRepeatTemplateAsynchronousTests extends - AbstractTradeBatchTests { - - RepeatTemplate template = getRepeatTemplate(); - - int count = 0; - - // @Override - public RepeatTemplate getRepeatTemplate() { - TaskExecutorRepeatTemplate template = new TaskExecutorRepeatTemplate(); - template.setTaskExecutor(new SimpleAsyncTaskExecutor()); - // Set default completion above number of items in input file - template.setCompletionPolicy(new SimpleCompletionPolicy(8)); - return template; - } - - @Test - public void testEarlyCompletionWithException() throws Exception { - - TaskExecutorRepeatTemplate template = new TaskExecutorRepeatTemplate(); - SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); - template.setCompletionPolicy(new SimpleCompletionPolicy(20)); - taskExecutor.setConcurrencyLimit(2); - template.setTaskExecutor(taskExecutor); - try { - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - throw new IllegalStateException("foo!"); - } - }); - fail("Expected IllegalStateException"); - } catch (IllegalStateException e) { - assertEquals("foo!", e.getMessage()); - } - - assertTrue("Too few attempts: " + count, count >= 1); - assertTrue("Too many attempts: " + count, count <= 10); - - } - - @Test - public void testExceptionHandlerSwallowsException() throws Exception { - - TaskExecutorRepeatTemplate template = new TaskExecutorRepeatTemplate(); - SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); - template.setCompletionPolicy(new SimpleCompletionPolicy(4)); - taskExecutor.setConcurrencyLimit(2); - template.setTaskExecutor(taskExecutor); - - template.setExceptionHandler(new ExceptionHandler() { - public void handleException(RepeatContext context, - Throwable throwable) throws Throwable { - count++; - } - }); - template.iterate(new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - throw new IllegalStateException("foo!"); - } - }); - - assertTrue("Too few attempts: " + count, count >= 1); - assertTrue("Too many attempts: " + count, count <= 10); - - } - - @Test - public void testNestedSession() throws Exception { - - RepeatTemplate outer = getRepeatTemplate(); - RepeatTemplate inner = new RepeatTemplate(); - - outer.iterate(new NestedRepeatCallback(inner, new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - assertNotNull(context); - assertNotSame("Nested batch should have new session", context, - context.getParent()); - assertSame(context, RepeatSynchronizationManager.getContext()); - return RepeatStatus.FINISHED; - } - }) { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - count++; - assertNotNull(context); - assertSame(context, RepeatSynchronizationManager.getContext()); - return super.doInIteration(context); - } - }); - - assertTrue("Too few attempts: " + count, count >= 1); - assertTrue("Too many attempts: " + count, count <= 10); - - } - - /** - * Run a batch with a single template that itself has an async task - * executor. The result is a batch that runs in multiple threads (up to the - * throttle limit of the template). - * - * @throws Exception - */ - @Test - public void testMultiThreadAsynchronousExecution() throws Exception { - - final String threadName = Thread.currentThread().getName(); - final Set threadNames = new HashSet(); - - final RepeatCallback callback = new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - assertNotSame(threadName, Thread.currentThread().getName()); - threadNames.add(Thread.currentThread().getName()); - Thread.sleep(100); - Trade item = provider.read(); - if (item != null) { - processor.write(Collections.singletonList(item)); - } - return RepeatStatus.continueIf(item != null); - } - }; - - template.iterate(callback); - // Shouldn't be necessary to wait: - // Thread.sleep(500); - assertEquals(NUMBER_OF_ITEMS, processor.count); - assertTrue(threadNames.size() > 1); - } - - @Test - public void testThrottleLimit() throws Exception { - - int throttleLimit = 600; - - TaskExecutorRepeatTemplate template = new TaskExecutorRepeatTemplate(); - SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); - taskExecutor.setConcurrencyLimit(300); - template.setTaskExecutor(taskExecutor); - template.setThrottleLimit(throttleLimit); - - final String threadName = Thread.currentThread().getName(); - final Set threadNames = new HashSet(); - final List items = new ArrayList(); - - final RepeatCallback callback = new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - assertNotSame(threadName, Thread.currentThread().getName()); - Trade item = provider.read(); - threadNames - .add(Thread.currentThread().getName() + " : " + item); - items.add("" + item); - if (item != null) { - processor.write(Collections.singletonList(item)); - // Do some more I/O - for (int i = 0; i < 10; i++) { - TradeReader provider = new TradeReader(); - while (provider.read() != null) - continue; - } - } - return RepeatStatus.continueIf(item != null); - } - }; - - template.iterate(callback); - // Shouldn't be necessary to wait: - // Thread.sleep(500); - assertEquals(NUMBER_OF_ITEMS, processor.count); - assertTrue(threadNames.size() > 1); - int frequency = Collections.frequency(items, "null"); - // System.err.println("Frequency: "+frequency); - assertTrue(frequency <= throttleLimit); - } - - /** - * Wrap an otherwise synchronous batch in a callback to an asynchronous - * template. - * - * @throws Exception - */ - @Test - public void testSingleThreadAsynchronousExecution() throws Exception { - TaskExecutorRepeatTemplate jobTemplate = new TaskExecutorRepeatTemplate(); - final RepeatTemplate stepTemplate = new RepeatTemplate(); - SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); - taskExecutor.setConcurrencyLimit(2); - jobTemplate.setTaskExecutor(taskExecutor); - - final String threadName = Thread.currentThread().getName(); - final Set threadNames = new HashSet(); - - final RepeatCallback stepCallback = new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - assertNotSame(threadName, Thread.currentThread().getName()); - threadNames.add(Thread.currentThread().getName()); - Thread.sleep(100); - Trade item = provider.read(); - if (item != null) { - processor.write(Collections.singletonList(item)); - } - return RepeatStatus.continueIf(item != null); - } - }; - RepeatCallback jobCallback = new RepeatCallback() { - public RepeatStatus doInIteration(RepeatContext context) - throws Exception { - stepTemplate.iterate(stepCallback); - return RepeatStatus.FINISHED; - } - }; - - jobTemplate.iterate(jobCallback); - // Shouldn't be necessary to wait: - // Thread.sleep(500); - assertEquals(NUMBER_OF_ITEMS, processor.count); - // Because of the throttling and queueing internally to a TaskExecutor, - // more than one thread will be used - the number used is the - // concurrency limit in the task executor, plus 1. - // System.err.println(threadNames); - assertTrue(threadNames.size() >= 1); - } - -} diff --git a/src/test/java/org/springframework/repeat/support/TaskExecutorRepeatTemplateBulkAsynchronousTests.java b/src/test/java/org/springframework/repeat/support/TaskExecutorRepeatTemplateBulkAsynchronousTests.java deleted file mode 100644 index 5a74a6f..0000000 --- a/src/test/java/org/springframework/repeat/support/TaskExecutorRepeatTemplateBulkAsynchronousTests.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.Before; -import org.junit.Test; -import org.springframework.core.task.SimpleAsyncTaskExecutor; -import org.springframework.repeat.RepeatCallback; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.RepeatStatus; -import org.springframework.repeat.policy.SimpleCompletionPolicy; - -/** - * Simple tests for concurrent behaviour in repeat template, in particular the - * barrier at the end of the iteration. N.B. these tests may fail if - * insufficient threads are available (e.g. on a single-core machine, or under - * load). They shouldn't deadlock though. - * - * @author Dave Syer - * - */ -public class TaskExecutorRepeatTemplateBulkAsynchronousTests { - - static Log logger = LogFactory.getLog(TaskExecutorRepeatTemplateBulkAsynchronousTests.class); - - private int total = 20; - - private int throttleLimit = 8; - - private volatile int early = Integer.MAX_VALUE; - - private TaskExecutorRepeatTemplate template; - - private RepeatCallback callback; - - private List items; - - @Before - public void setUp() { - - template = new TaskExecutorRepeatTemplate(); - SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); - taskExecutor.setConcurrencyLimit(300); - template.setTaskExecutor(taskExecutor); - template.setThrottleLimit(throttleLimit); - - items = Collections.synchronizedList(new ArrayList()); - - callback = new RepeatCallback() { - - private volatile AtomicInteger count = new AtomicInteger(0); - - public RepeatStatus doInIteration(RepeatContext context) throws Exception { - int position = count.incrementAndGet(); - String item = position <= total ? "" + position : null; - items.add("" + item); - if (item != null) { - beBusy(); - } - /* - * In a multi-threaded task, one of the callbacks can call - * FINISHED early, while other threads are still working, and - * would do more work if the callback was called again. (This - * happens for instance if there is a failure and you want to - * retry the work.) - */ - RepeatStatus result = RepeatStatus.continueIf(position != early && item != null); - if (!result.isContinuable()) { - logger.debug("Returning " + result + " for count=" + position); - } - return result; - } - }; - - } - - @Test - public void testThrottleLimit() throws Exception { - - template.iterate(callback); - int frequency = Collections.frequency(items, "null"); - // System.err.println(items); - // System.err.println("Frequency: " + frequency); - assertEquals(total, items.size() - frequency); - assertTrue(frequency > 1); - assertTrue(frequency <= throttleLimit + 1); - - } - - @Test - public void testThrottleLimitEarlyFinish() throws Exception { - - early = 2; - - template.iterate(callback); - int frequency = Collections.frequency(items, "null"); - // System.err.println("Frequency: " + frequency); - // System.err.println("Items: " + items); - assertEquals(total, items.size() - frequency); - assertTrue(frequency > 1); - assertTrue(frequency <= throttleLimit + 1); - - } - - @Test - public void testThrottleLimitEarlyFinishThreadStarvation() throws Exception { - - early = 2; - SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); - // Set the concurrency limit below the throttle limit for possible - // starvation condition - taskExecutor.setConcurrencyLimit(20); - template.setTaskExecutor(taskExecutor); - - template.iterate(callback); - int frequency = Collections.frequency(items, "null"); - // System.err.println("Frequency: " + frequency); - // System.err.println("Items: " + items); - // Extra tasks will be submitted before the termination is detected - assertEquals(total, items.size() - frequency); - assertTrue(frequency <= throttleLimit + 1); - - } - - @Test - public void testThrottleLimitEarlyFinishOneThread() throws Exception { - - early = 4; - SimpleAsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(); - taskExecutor.setConcurrencyLimit(1); - - // This is kind of slow with only one thread, so reduce size: - throttleLimit = 4; - total = 10; - - template.setThrottleLimit(throttleLimit); - template.setTaskExecutor(taskExecutor); - - template.iterate(callback); - int frequency = Collections.frequency(items, "null"); - // System.err.println("Frequency: " + frequency); - // System.err.println("Items: " + items); - assertEquals(total, items.size() - frequency); - assertTrue(frequency <= throttleLimit + 1); - - } - - @Test - public void testThrottleLimitWithEarlyCompletion() throws Exception { - - early = 2; - template.setCompletionPolicy(new SimpleCompletionPolicy(10)); - - template.iterate(callback); - int frequency = Collections.frequency(items, "null"); - assertEquals(10, items.size() - frequency); - // System.err.println("Frequency: " + frequency); - assertEquals(0, frequency); - - } - - /** - * Slightly flakey convenience method. If this doesn't do something that - * lasts sufficiently long for another worker to be launched while it is - * busy, the early completion tests will fail. "Sufficiently long" is the - * problem so we try and block until we know someone else is busy? - * - * @throws Exception - */ - private void beBusy() throws Exception { - synchronized (this) { - wait(100L); - notifyAll(); - } - } - -} diff --git a/src/test/java/org/springframework/repeat/support/TaskExecutorRepeatTemplateTests.java b/src/test/java/org/springframework/repeat/support/TaskExecutorRepeatTemplateTests.java deleted file mode 100644 index 28289c0..0000000 --- a/src/test/java/org/springframework/repeat/support/TaskExecutorRepeatTemplateTests.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import static org.junit.Assert.fail; - -import org.junit.Test; - - -/** - * @author Dave Syer - */ -public class TaskExecutorRepeatTemplateTests extends SimpleRepeatTemplateTests { - - public RepeatTemplate getRepeatTemplate() { - return new TaskExecutorRepeatTemplate(); - } - - @Test - public void testSetThrottleLimit() throws Exception { - try { - new TaskExecutorRepeatTemplate().setThrottleLimit(-1); - } catch (Exception e) { - // unexpected - no check for illegal values - fail("Unexpected Exception setting throttle limit"); - } - } - -} diff --git a/src/test/java/org/springframework/repeat/support/ThrottleLimitResultQueueTests.java b/src/test/java/org/springframework/repeat/support/ThrottleLimitResultQueueTests.java deleted file mode 100644 index 7d43e0c..0000000 --- a/src/test/java/org/springframework/repeat/support/ThrottleLimitResultQueueTests.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.repeat.support; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.NoSuchElementException; - -import org.junit.Test; - - -/** - * @author Dave Syer - * - */ -public class ThrottleLimitResultQueueTests { - - private ThrottleLimitResultQueue queue = new ThrottleLimitResultQueue(1); - - @Test - public void testPutTake() throws Exception { - queue.expect(); - assertTrue(queue.isExpecting()); - assertTrue(queue.isEmpty()); - queue.put("foo"); - assertFalse(queue.isEmpty()); - assertEquals("foo", queue.take()); - assertFalse(queue.isExpecting()); - } - - @Test - public void testPutWithoutExpecting() throws Exception { - assertFalse(queue.isExpecting()); - try { - queue.put("foo"); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } - } - - @Test - public void testTakeWithoutExpecting() throws Exception { - assertFalse(queue.isExpecting()); - try { - queue.take(); - fail("Expected NoSuchElementException"); - } catch (NoSuchElementException e) { - // expected - } - } - - @Test - public void testThrottleLimit() throws Exception { - queue.expect(); - new Thread(new Runnable() { - public void run() { - try { - Thread.sleep(100L); - } - catch (InterruptedException e) { - e.printStackTrace(); - Thread.currentThread().interrupt(); - } - queue.put("foo"); - } - }).start(); - long t0 = System.currentTimeMillis(); - queue.expect(); - long t1 = System.currentTimeMillis(); - assertEquals("foo", queue.take()); - assertTrue(queue.isExpecting()); - assertTrue("Did not block on expect (throttle limit should have been hit): time taken="+(t1-t0), t1-t0>50); - } - -} diff --git a/src/test/java/org/springframework/repeat/support/Trade.java b/src/test/java/org/springframework/repeat/support/Trade.java deleted file mode 100644 index 66429bb..0000000 --- a/src/test/java/org/springframework/repeat/support/Trade.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.repeat.support; - -import java.math.BigDecimal; - -/** - * @author Rob Harrop - */ -public class Trade { - - private String isin; - - private long quantity; - - private BigDecimal price; - - Trade(String isin, long quantity, String price) { - this.isin = isin; - this.quantity = quantity; - this.price = new BigDecimal(price); - } - - public String getIsin() { - return isin; - } - - public BigDecimal getPrice() { - return price; - } - - public long getQuantity() { - return quantity; - } - - public String toString() { - return "Trade: [isin=" + isin + ",quantity=" + quantity + ",price=" + price + "]"; - } -} diff --git a/src/test/java/org/springframework/retry/support/StatefulRecoveryRetryTests.java b/src/test/java/org/springframework/retry/support/StatefulRecoveryRetryTests.java index 919bef9..65ee145 100644 --- a/src/test/java/org/springframework/retry/support/StatefulRecoveryRetryTests.java +++ b/src/test/java/org/springframework/retry/support/StatefulRecoveryRetryTests.java @@ -29,9 +29,6 @@ import java.util.List; import org.junit.Test; import org.springframework.classify.BinaryExceptionClassifier; import org.springframework.dao.DataAccessException; -import org.springframework.repeat.RepeatContext; -import org.springframework.repeat.context.RepeatContextSupport; -import org.springframework.repeat.support.RepeatSynchronizationManager; import org.springframework.retry.ExhaustedRetryException; import org.springframework.retry.RecoveryCallback; import org.springframework.retry.RetryCallback; @@ -83,15 +80,6 @@ public class StatefulRecoveryRetryTests { assertFalse(retryPolicy.canRetry(context)); } - @Test - public void testRecoverWithParent() throws Exception { - RepeatContext parent = new RepeatContextSupport(null); - RepeatSynchronizationManager.register(new RepeatContextSupport(parent)); - testRecover(); - assertFalse(parent.isCompleteOnly()); - RepeatSynchronizationManager.clear(); - } - @Test public void testRecover() throws Exception { retryTemplate.setRetryPolicy(new SimpleRetryPolicy(1, Collections