blob: 1ca09384a59e74adfffbeabe4afa25f71a0bc592 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0, which accompanies this distribution
* and is available at https://www.eclipse.org/legal/epl-2.0/.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.common.utility.internal.closure;
import org.eclipse.jpt.common.utility.Association;
import org.eclipse.jpt.common.utility.closure.Closure;
import org.eclipse.jpt.common.utility.command.Command;
import org.eclipse.jpt.common.utility.exception.ExceptionHandler;
import org.eclipse.jpt.common.utility.factory.Factory;
import org.eclipse.jpt.common.utility.internal.ArrayTools;
import org.eclipse.jpt.common.utility.internal.ClassTools;
import org.eclipse.jpt.common.utility.internal.ObjectTools;
import org.eclipse.jpt.common.utility.internal.command.NullCommand;
import org.eclipse.jpt.common.utility.internal.exception.DefaultExceptionHandler;
import org.eclipse.jpt.common.utility.predicate.Predicate;
import org.eclipse.jpt.common.utility.transformer.Transformer;
/**
* {@link Closure} utility methods.
*/
public final class ClosureTools {
// ********** adapters **********
/**
* Adapt the specified {@link Command} to the {@link Closure} interface.
* The closure's argument is ignored.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> adapt(Command command) {
return new CommandClosure<A>(command);
}
/**
* Adapt the specified {@link Factory} to the {@link Closure} interface.
* The closure's argument and the factory's output are ignored. This really
* only useful for a factory that has side-effects.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> adapt(Factory<?> factory) {
return new FactoryClosure<A>(factory);
}
/**
* Adapt the specified {@link Transformer} to the {@link Closure} interface.
* The transformer's output is ignored. This really only useful for a
* transformer that has side-effects.
* @param <A> the type of the object passed to the closure and forwarded to
* the transformer
*/
public static <A> Closure<A> adapt(Transformer<? super A, ?> transformer) {
return new TransformerClosure<A>(transformer);
}
// ********** thread local **********
/**
* Return a closure that allows the client to specify a different closure
* for each thread. If there is no closure for the current thread, the
* closure will do nothing.
* @param <A> the type of the object passed to the closure
* @see ThreadLocalClosure
*/
public static <A> ThreadLocalClosure<A> threadLocalClosure() {
return threadLocalClosure(NullClosure.instance());
}
/**
* Return a closure that allows the client to specify a different closure
* for each thread. If there is no closure for the current thread, the
* specified default closure is executed.
* @param <A> the type of the object passed to the closure
* @see ThreadLocalClosure
*/
public static <A> ThreadLocalClosure<A> threadLocalClosure(Closure<? super A> defaultClosure) {
return new ThreadLocalClosure<A>(defaultClosure);
}
// ********** wrappers **********
/**
* Return a closure that wraps the specified closure and checks
* for a <code>null</code> argument before forwarding the argument to the
* specified closure. If the argument is <code>null</code>, the closure will
* do nothing.
* @param <A> the type of the object passed to the closure
* @see #nullCheck(Closure, Command)
*/
public static <A> Closure<A> nullCheck(Closure<? super A> closure) {
return nullCheck(closure, NullCommand.instance());
}
/**
* Return a closure that wraps the specified closure and checks
* for a <code>null</code> argument before forwarding the argument to the
* specified closure. If the argument is <code>null</code>,
* the closure will execute the specified command.
* @param <A> the type of the object passed to the closure
* @see #nullCheck(Closure)
*/
public static <A> Closure<A> nullCheck(Closure<? super A> closure, Command nullCommand) {
return new NullCheckClosureWrapper<A>(closure, nullCommand);
}
/**
* Return a closure that can have its wrapped closure changed,
* allowing a client to change a previously-supplied closure's
* behavior mid-stream.
* @param <A> the type of the object passed to the closure
* @see ClosureWrapper
*/
public static <A> ClosureWrapper<A> wrap(Closure<? super A> closure) {
return new ClosureWrapper<A>(closure);
}
// ********** safe **********
/**
* Return closure that will handle any exceptions thrown by the specified
* closure. If the wrapped closure throws an exception,
* the exception's stack trace will be printed to {@link System#err
* the "standard" error output stream}.
* @param <A> the type of the object passed to the closure
* @see #safe(Closure, ExceptionHandler)
*/
public static <A> Closure<A> safe(Closure<? super A> closure) {
return safe(closure, DefaultExceptionHandler.instance());
}
/**
* Return closure that will handle any exceptions thrown by the specified
* closure with the specified exception handler. If the
* wrapped closure throws an exception, the safe closure will handle
* the exception and return.
* @param <A> the type of the object passed to the closure
* @see #safe(Closure)
*/
public static <A> Closure<A> safe(Closure<? super A> closure, ExceptionHandler exceptionHandler) {
return new SafeClosureWrapper<A>(closure, exceptionHandler);
}
// ********** reflection **********
/**
* Return a closure that uses Java reflection to invoke the specified
* zero-argument method on the argument.
* <p>
* <strong>NB:</strong> The actual method is determined at execution time,
* not construction time. As a result, the closure can be used to emulate
* "duck typing".
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> execute(String methodName) {
return execute(methodName, ClassTools.EMPTY_ARRAY, ObjectTools.EMPTY_OBJECT_ARRAY);
}
/**
* Return a closure that uses Java reflection to invoke the specified
* single-argument method on the argument.
* <p>
* <strong>NB:</strong> The actual method is determined at execution time,
* not construction time. As a result, the closure can be used to emulate
* "duck typing".
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> execute(String methodName, Class<?> parameterType, Object argument) {
return execute(methodName, new Class<?>[] { parameterType }, new Object[] { argument });
}
/**
* Return a closure that uses Java reflection to invoke the specified method
* on the argument.
* <p>
* <strong>NB:</strong> The actual method is determined at execution time,
* not construction time. As a result, the closure can be used to emulate
* "duck typing".
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> execute(String methodName, Class<?>[] parameterTypes, Object[] arguments) {
return new MethodClosure<A>(methodName, parameterTypes, arguments);
}
// ********** composite **********
/**
* Return a composite of the specified closures. The composite's argument
* will be passed to each closure, in sequence.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> composite(Closure<? super A>... closures) {
return composite(ArrayTools.iterable(closures));
}
/**
* Return a composite of the specified closures. The composite's argument
* will be passed to each closure, in sequence.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> composite(Iterable<Closure<? super A>> closures) {
return new CompositeClosure<A>(closures);
}
// ********** conditional **********
/**
* Return a closure that passes its argument to the specified predicate to
* determine whether to execute the specified closure.
* If the predicate evaluates to <code>false</code>, the closure will do
* nothing.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> conditionalClosure(Predicate<? super A> predicate, Closure<? super A> closure) {
return conditionalClosure(predicate, closure, NullClosure.instance());
}
/**
* Return a closure that passes its argument to the specified predicate to
* determine which of the two specified closures to execute.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> conditionalClosure(Predicate<? super A> predicate, Closure<? super A> trueClosure, Closure<? super A> falseClosure) {
return new ConditionalClosure<A>(predicate, trueClosure, falseClosure);
}
// ********** switch **********
/**
* Return a closure that loops over the specified set of predicate/closure
* pairs, passing its argument to each predicate to determine
* which of the closures to execute. Only the first closure whose predicate
* evaluates to <code>true</code> is executed, even if other, following,
* predicates would evaluate to <code>true</code>.
* If none of the predicates evaluates to <code>true</code>, the closure
* will do nothing.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> switchClosure(Iterable<Association<Predicate<? super A>, Closure<? super A>>> closures) {
return switchClosure(closures, NullClosure.instance());
}
/**
* Return a closure that loops over the specified set of predicate/closure
* pairs, passing its argument to each predicate to determine
* which of the closures to execute. Only the first closure whose predicate
* evaluates to <code>true</code> is executed, even if other, following,
* predicates would evaluate to <code>true</code>.
* If none of the predicates evaluates to <code>true</code>, the specified
* default closure is executed.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> switchClosure(Iterable<Association<Predicate<? super A>, Closure<? super A>>> closures, Closure<? super A> defaultClosure) {
return new SwitchClosure<A>(closures, defaultClosure);
}
// ********** disabled **********
/**
* Return a closure that will throw an
* {@link UnsupportedOperationException exception} when executed.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> disabledClosure() {
return DisabledClosure.instance();
}
// ********** looping **********
/**
* Return a closure that executes the specified closure the specified
* number of times.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> repeat(Closure<? super A> closure, int count) {
return new RepeatingClosure<A>(closure, count);
}
/**
* Return a closure that executes the specified closure while the specified
* predicate evaluates to <code>true</code> when passed the argument.
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> while_(Predicate<? super A> predicate, Closure<? super A> closure) {
return new WhileClosure<A>(predicate, closure);
}
/**
* Return a closure that executes the specified closure until the specified
* predicate evaluates to <code>true</code> when passed the argument. The
* specifie closure will always execute at least once.
* <p>
* <strong>NB:</strong> This is the inverse of the Java <code>do-while</code>
* statement (i.e. it executes until the predicate evaluates to
* <strong><code>true</code></strong>,
* <em>not</em> <code>false</code>).
* @param <A> the type of the object passed to the closure
*/
public static <A> Closure<A> until(Closure<? super A> closure, Predicate<? super A> predicate) {
return new UntilClosure<A>(closure, predicate);
}
// ********** constructor **********
/**
* Suppress default constructor, ensuring non-instantiability.
*/
private ClosureTools() {
super();
throw new UnsupportedOperationException();
}
}