001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.collections4;
018
019import java.util.Collection;
020import java.util.Map;
021
022import org.apache.commons.collections4.functors.ChainedTransformer;
023import org.apache.commons.collections4.functors.CloneTransformer;
024import org.apache.commons.collections4.functors.ClosureTransformer;
025import org.apache.commons.collections4.functors.ConstantTransformer;
026import org.apache.commons.collections4.functors.EqualPredicate;
027import org.apache.commons.collections4.functors.ExceptionTransformer;
028import org.apache.commons.collections4.functors.FactoryTransformer;
029import org.apache.commons.collections4.functors.InstantiateTransformer;
030import org.apache.commons.collections4.functors.InvokerTransformer;
031import org.apache.commons.collections4.functors.MapTransformer;
032import org.apache.commons.collections4.functors.NOPTransformer;
033import org.apache.commons.collections4.functors.PredicateTransformer;
034import org.apache.commons.collections4.functors.StringValueTransformer;
035import org.apache.commons.collections4.functors.SwitchTransformer;
036
037/**
038 * <code>TransformerUtils</code> provides reference implementations and
039 * utilities for the Transformer functor interface. The supplied transformers are:
040 * <ul>
041 * <li>Invoker - returns the result of a method call on the input object
042 * <li>Clone - returns a clone of the input object
043 * <li>Constant - always returns the same object
044 * <li>Closure - performs a Closure and returns the input object
045 * <li>Predicate - returns the result of the predicate as a Boolean
046 * <li>Factory - returns a new object from a factory
047 * <li>Chained - chains two or more transformers together
048 * <li>Switch - calls one transformer based on one or more predicates
049 * <li>SwitchMap - calls one transformer looked up from a Map
050 * <li>Instantiate - the Class input object is instantiated
051 * <li>Map - returns an object from a supplied Map
052 * <li>Null - always returns null
053 * <li>NOP - returns the input object, which should be immutable
054 * <li>Exception - always throws an exception
055 * <li>StringValue - returns a <code>java.lang.String</code> representation of the input object
056 * </ul>
057 * All the supplied transformers are Serializable.
058 *
059 * @since 3.0
060 * @version $Id: TransformerUtils.html 972421 2015-11-14 20:00:04Z tn $
061 */
062public class TransformerUtils {
063
064    /**
065     * This class is not normally instantiated.
066     */
067    private TransformerUtils() {}
068
069    /**
070     * Gets a transformer that always throws an exception.
071     * This could be useful during testing as a placeholder.
072     *
073     * @param <I>  the input type
074     * @param <O>  the output type
075     * @return the transformer
076     * @see org.apache.commons.collections4.functors.ExceptionTransformer
077     */
078    public static <I, O> Transformer<I, O> exceptionTransformer() {
079        return ExceptionTransformer.<I, O>exceptionTransformer();
080    }
081
082    /**
083     * Gets a transformer that always returns null.
084     *
085     * @param <I>  the input type
086     * @param <O>  the output type
087     * @return the transformer
088     * @see org.apache.commons.collections4.functors.ConstantTransformer
089     */
090    public static <I, O> Transformer<I, O> nullTransformer() {
091        return ConstantTransformer.<I, O>nullTransformer();
092    }
093
094    /**
095     * Gets a transformer that returns the input object.
096     * The input object should be immutable to maintain the
097     * contract of Transformer (although this is not checked).
098     *
099     * @param <T>  the input/output type
100     * @return the transformer
101     * @see org.apache.commons.collections4.functors.NOPTransformer
102     */
103    public static <T> Transformer<T, T> nopTransformer() {
104        return NOPTransformer.<T>nopTransformer();
105    }
106
107    /**
108     * Gets a transformer that returns a clone of the input
109     * object. The input object will be cloned using one of these
110     * techniques (in order):
111     * <ul>
112     * <li>public clone method
113     * <li>public copy constructor
114     * <li>serialization clone
115     * <ul>
116     *
117     * @param <T>  the input/output type
118     * @return the transformer
119     * @see org.apache.commons.collections4.functors.CloneTransformer
120     */
121    public static <T> Transformer<T, T> cloneTransformer() {
122        return CloneTransformer.<T>cloneTransformer();
123    }
124
125    /**
126     * Creates a Transformer that will return the same object each time the
127     * transformer is used.
128     *
129     * @param <I>  the input type
130     * @param <O>  the output type
131     * @param constantToReturn  the constant object to return each time in the transformer
132     * @return the transformer.
133     * @see org.apache.commons.collections4.functors.ConstantTransformer
134     */
135    public static <I, O> Transformer<I, O> constantTransformer(final O constantToReturn) {
136        return ConstantTransformer.constantTransformer(constantToReturn);
137    }
138
139    /**
140     * Creates a Transformer that calls a Closure each time the transformer is used.
141     * The transformer returns the input object.
142     *
143     * @param <T>  the input/output type
144     * @param closure  the closure to run each time in the transformer, not null
145     * @return the transformer
146     * @throws IllegalArgumentException if the closure is null
147     * @see org.apache.commons.collections4.functors.ClosureTransformer
148     */
149    public static <T> Transformer<T, T> asTransformer(final Closure<? super T> closure) {
150        return ClosureTransformer.closureTransformer(closure);
151    }
152
153    /**
154     * Creates a Transformer that calls a Predicate each time the transformer is used.
155     * The transformer will return either Boolean.TRUE or Boolean.FALSE.
156     *
157     * @param <T>  the input type
158     * @param predicate  the predicate to run each time in the transformer, not null
159     * @return the transformer
160     * @throws IllegalArgumentException if the predicate is null
161     * @see org.apache.commons.collections4.functors.PredicateTransformer
162     */
163    public static <T> Transformer<T, Boolean> asTransformer(final Predicate<? super T> predicate) {
164        return PredicateTransformer.predicateTransformer(predicate);
165    }
166
167    /**
168     * Creates a Transformer that calls a Factory each time the transformer is used.
169     * The transformer will return the value returned by the factory.
170     *
171     * @param <I>  the input type
172     * @param <O>  the output type
173     * @param factory  the factory to run each time in the transformer, not null
174     * @return the transformer
175     * @throws IllegalArgumentException if the factory is null
176     * @see org.apache.commons.collections4.functors.FactoryTransformer
177     */
178    public static <I, O> Transformer<I, O> asTransformer(final Factory<? extends O> factory) {
179        return FactoryTransformer.factoryTransformer(factory);
180    }
181
182    /**
183     * Create a new Transformer that calls each transformer in turn, passing the
184     * result into the next transformer.
185     *
186     * @param <T>  the input/output type
187     * @param transformers  an array of transformers to chain
188     * @return the transformer
189     * @throws IllegalArgumentException if the transformers array or any of the transformers is null
190     * @see org.apache.commons.collections4.functors.ChainedTransformer
191     */
192    public static <T> Transformer<T, T> chainedTransformer(
193            final Transformer<? super T, ? extends T>... transformers) {
194        return ChainedTransformer.chainedTransformer(transformers);
195    }
196
197    /**
198     * Create a new Transformer that calls each transformer in turn, passing the
199     * result into the next transformer. The ordering is that of the iterator()
200     * method on the collection.
201     *
202     * @param <T>  the input/output type
203     * @param transformers  a collection of transformers to chain
204     * @return the transformer
205     * @throws IllegalArgumentException if the transformers collection or any of the transformers is null
206     * @see org.apache.commons.collections4.functors.ChainedTransformer
207     */
208    public static <T> Transformer<T, T> chainedTransformer(
209            final Collection<? extends Transformer<T, T>> transformers) {
210        return ChainedTransformer.chainedTransformer(transformers);
211    }
212
213    /**
214     * Create a new Transformer that calls one of two transformers depending
215     * on the specified predicate.
216     *
217     * @param <I>  the input type
218     * @param <O>  the output type
219     * @param predicate  the predicate to switch on
220     * @param trueTransformer  the transformer called if the predicate is true
221     * @param falseTransformer  the transformer called if the predicate is false
222     * @return the transformer
223     * @throws IllegalArgumentException if either the predicate or transformer is null
224     * @see org.apache.commons.collections4.functors.SwitchTransformer
225     */
226    @SuppressWarnings("unchecked")
227    public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I> predicate,
228            final Transformer<? super I, ? extends O> trueTransformer,
229            final Transformer<? super I, ? extends O> falseTransformer) {
230        return SwitchTransformer.switchTransformer(new Predicate[] { predicate },
231                                                   new Transformer[] { trueTransformer }, falseTransformer);
232    }
233
234    /**
235     * Create a new Transformer that calls one of the transformers depending
236     * on the predicates. The transformer at array location 0 is called if the
237     * predicate at array location 0 returned true. Each predicate is evaluated
238     * until one returns true. If no predicates evaluate to true, null is returned.
239     *
240     * @param <I>  the input type
241     * @param <O>  the output type
242     * @param predicates  an array of predicates to check
243     * @param transformers  an array of transformers to call
244     * @return the transformer
245     * @throws IllegalArgumentException if the either array is null or empty
246     * @throws IllegalArgumentException if any element in the arrays is null
247     * @throws IllegalArgumentException if the arrays are different sizes
248     * @see org.apache.commons.collections4.functors.SwitchTransformer
249     */
250    public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
251            final Transformer<? super I, ? extends O>[] transformers) {
252        return SwitchTransformer.<I, O>switchTransformer(predicates, transformers, null);
253    }
254
255    /**
256     * Create a new Transformer that calls one of the transformers depending
257     * on the predicates. The transformer at array location 0 is called if the
258     * predicate at array location 0 returned true. Each predicate is evaluated
259     * until one returns true. If no predicates evaluate to true, the default
260     * transformer is called. If the default transformer is null, null is returned.
261     *
262     * @param <I>  the input type
263     * @param <O>  the output type
264     * @param predicates  an array of predicates to check
265     * @param transformers  an array of transformers to call
266     * @param defaultTransformer  the default to call if no predicate matches, null means return null
267     * @return the transformer
268     * @throws IllegalArgumentException if the either array is null or empty
269     * @throws IllegalArgumentException if any element in the arrays is null
270     * @throws IllegalArgumentException if the arrays are different sizes
271     * @see org.apache.commons.collections4.functors.SwitchTransformer
272     */
273    public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
274            final Transformer<? super I, ? extends O>[] transformers,
275            final Transformer<? super I, ? extends O> defaultTransformer) {
276        return SwitchTransformer.<I, O>switchTransformer(predicates, transformers, defaultTransformer);
277    }
278
279    /**
280     * Create a new Transformer that calls one of the transformers depending
281     * on the predicates.
282     * <p>
283     * The Map consists of Predicate keys and Transformer values. A transformer
284     * is called if its matching predicate returns true. Each predicate is evaluated
285     * until one returns true. If no predicates evaluate to true, the default
286     * transformer is called. The default transformer is set in the map with a
287     * null key. If no default transformer is set, null will be returned in a default
288     * case. The ordering is that of the iterator() method on the entryset collection
289     * of the map.
290     *
291     * @param <I>  the input type
292     * @param <O>  the output type
293     * @param predicatesAndTransformers  a map of predicates to transformers
294     * @return the transformer
295     * @throws IllegalArgumentException if the map is null or empty
296     * @throws IllegalArgumentException if any transformer in the map is null
297     * @throws ClassCastException  if the map elements are of the wrong type
298     * @see org.apache.commons.collections4.functors.SwitchTransformer
299     */
300    public static <I, O> Transformer<I, O> switchTransformer(
301            final Map<Predicate<I>, Transformer<I, O>> predicatesAndTransformers) {
302        return SwitchTransformer.<I, O>switchTransformer(predicatesAndTransformers);
303    }
304
305    /**
306     * Create a new Transformer that uses the input object as a key to find the
307     * transformer to call.
308     * <p>
309     * The Map consists of object keys and Transformer values. A transformer
310     * is called if the input object equals the key. If there is no match, the
311     * default transformer is called. The default transformer is set in the map
312     * using a null key. If no default is set, null will be returned in a default case.
313     *
314     * @param <I>  the input type
315     * @param <O>  the output type
316     * @param objectsAndTransformers  a map of objects to transformers
317     * @return the transformer
318     * @throws IllegalArgumentException if the map is null or empty
319     * @throws IllegalArgumentException if any transformer in the map is null
320     * @see org.apache.commons.collections4.functors.SwitchTransformer
321     */
322    @SuppressWarnings("unchecked")
323    public static <I, O> Transformer<I, O> switchMapTransformer(
324            final Map<I, Transformer<I, O>> objectsAndTransformers) {
325
326        if (objectsAndTransformers == null) {
327            throw new IllegalArgumentException("The object and transformer map must not be null");
328        }
329        final Transformer<? super I, ? extends O> def = objectsAndTransformers.remove(null);
330        final int size = objectsAndTransformers.size();
331        final Transformer<? super I, ? extends O>[] trs = new Transformer[size];
332        final Predicate<I>[] preds = new Predicate[size];
333        int i = 0;
334        for (final Map.Entry<I, Transformer<I, O>> entry : objectsAndTransformers.entrySet()) {
335            preds[i] = EqualPredicate.<I>equalPredicate(entry.getKey());
336            trs[i++] = entry.getValue();
337        }
338        return TransformerUtils.<I, O>switchTransformer(preds, trs, def);
339    }
340
341    /**
342     * Gets a Transformer that expects an input Class object that it will instantiate.
343     *
344     * @param <T>  the output type
345     * @return the transformer
346     * @see org.apache.commons.collections4.functors.InstantiateTransformer
347     */
348    public static <T> Transformer<Class<? extends T>, T> instantiateTransformer() {
349        return InstantiateTransformer.<T>instantiateTransformer();
350    }
351
352    /**
353     * Creates a Transformer that expects an input Class object that it will
354     * instantiate. The constructor used is determined by the arguments specified
355     * to this method.
356     *
357     * @param <T>  the output type
358     * @param paramTypes  parameter types for the constructor, can be null
359     * @param args  the arguments to pass to the constructor, can be null
360     * @return the transformer
361     * @throws IllegalArgumentException if the paramTypes and args don't match
362     * @see org.apache.commons.collections4.functors.InstantiateTransformer
363     */
364    public static <T> Transformer<Class<? extends T>, T> instantiateTransformer(
365            final Class<?>[] paramTypes, final Object[] args) {
366        return InstantiateTransformer.<T>instantiateTransformer(paramTypes, args);
367    }
368
369    /**
370     * Creates a Transformer that uses the passed in Map to transform the input
371     * object (as a simple lookup).
372     *
373     * @param <I>  the input type
374     * @param <O>  the output type
375     * @param map  the map to use to transform the objects
376     * @return the transformer, or a {@link ConstantTransformer#NULL_INSTANCE} if the {@code map} is {@code null}
377     * @see org.apache.commons.collections4.functors.MapTransformer
378     */
379    public static <I, O> Transformer<I, O> mapTransformer(final Map<? super I, ? extends O> map) {
380        return MapTransformer.mapTransformer(map);
381    }
382
383    /**
384     * Gets a Transformer that invokes a method on the input object.
385     * The method must have no parameters. If the input object is null,
386     * null is returned.
387     * <p>
388     * For example, <code>TransformerUtils.invokerTransformer("getName");</code>
389     * will call the <code>getName/code> method on the input object to
390     * determine the transformer result.
391     *
392     * @param <I>  the input type
393     * @param <O>  the output type
394     * @param methodName  the method name to call on the input object, may not be null
395     * @return the transformer
396     * @throws IllegalArgumentException if the methodName is null.
397     * @see org.apache.commons.collections4.functors.InvokerTransformer
398     */
399    public static <I, O> Transformer<I, O> invokerTransformer(final String methodName) {
400        return InvokerTransformer.<I, O>invokerTransformer(methodName, null, null);
401    }
402
403    /**
404     * Gets a Transformer that invokes a method on the input object.
405     * The method parameters are specified. If the input object is {@code null},
406     * {@code null} is returned.
407     *
408     * @param <I>  the input type
409     * @param <O>  the output type
410     * @param methodName  the name of the method
411     * @param paramTypes  the parameter types
412     * @param args  the arguments
413     * @return the transformer
414     * @throws IllegalArgumentException if the method name is null or the paramTypes and args don't match
415     * @see org.apache.commons.collections4.functors.InvokerTransformer
416     */
417    public static <I, O> Transformer<I, O> invokerTransformer(final String methodName, final Class<?>[] paramTypes,
418                                                              final Object[] args) {
419        return InvokerTransformer.<I, O>invokerTransformer(methodName, paramTypes, args);
420    }
421
422    /**
423     * Gets a transformer that returns a <code>java.lang.String</code>
424     * representation of the input object. This is achieved via the
425     * <code>toString</code> method, <code>null</code> returns 'null'.
426     *
427     * @param <T>  the input type
428     * @return the transformer
429     * @see org.apache.commons.collections4.functors.StringValueTransformer
430     */
431    public static <T> Transformer<T, String> stringValueTransformer() {
432        return StringValueTransformer.<T>stringValueTransformer();
433    }
434
435}