    001    // Copyright 2010, 2011 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    // http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.func;
    016
    017    import java.util.Collection;
    018    import java.util.Comparator;
    019    import java.util.Iterator;
    020    import java.util.Map;
    021    import java.util.Map.Entry;
    022
    023    /**
    024     * Functional operations on collections with generics support. The core interface is {@link Flow} to
    025     * which operations
    026     * and transformations
    027     * (in terms of {@link Predicate}s, {@link Mapper}s and {@link Reducer}s) to create new Flows. Flows
    028     * are initially
    029     * created
    030     * using {@link #flow(Collection)} and {@link #flow(Object...)}.
    031     * <p/>
    032     * F will be used a bit, thus it has a short name (for those who don't like static imports). It provides a base set of
    033     * Predicate, Mapper and Reducer factories. A good development pattern for applications is to provide a similar,
    034     * application-specific, set of such factories.
    035     *
    036     * @since 5.2.0
    037     */
    038    @SuppressWarnings("all")
    039    public class F
    040    {
    041        final static Flow<?> EMPTY_FLOW = new EmptyFlow();
    042
    043        @SuppressWarnings("unchecked")
    044        static <T> Flow<T> emptyFlow()
    045        {
    046            return (Flow<T>) EMPTY_FLOW;
    047        }
    048
    049        /**
    050         * A Predicate factory for equality of an element from a flow against a specified
    051         * value.
    052         */
    053        public static <T> Predicate<T> eql(final T value)
    054        {
    055            return new Predicate<T>()
    056            {
    057                public boolean accept(T element)
    058                {
    059                    return element.equals(value);
    060                }
    061            };
    062        }
    063
    064        /**
    065         * A Predicate factory for comparison of a Comparable element from a flow against a fixed value.
    066         */
    067        public static <T extends Comparable<T>> Predicate<T> eq(final T value)
    068        {
    069            return new Predicate<T>()
    070            {
    071                public boolean accept(T element)
    072                {
    073                    return element.compareTo(value) == 0;
    074                }
    075            };
    076        }
    077
    078        /**
    079         * A Predicate factory for comparison of a Comparable element against a fixed value.
    080         */
    081        public static <T extends Comparable<T>> Predicate<T> neq(final T value)
    082        {
    083            return new Predicate<T>()
    084            {
    085                public boolean accept(T object)
    086                {
    087                    return object.compareTo(value) != 0;
    088                }
    089            };
    090        }
    091
    092        /**
    093         * A Predicate factory for comparison of a Comparable against a fixed value; true
    094         * if the flow element is greater than the provided value.
    095         */
    096        public static <T extends Comparable<T>> Predicate<T> gt(final T value)
    097        {
    098            return new Predicate<T>()
    099            {
    100                public boolean accept(T element)
    101                {
    102                    return element.compareTo(value) > 0;
    103                }
    104            };
    105        }
    106
    107        /**
    108         * A Predicate factory for comparison of a Comparable against a fixed value; true
    109         * if the flow element is greater than or equal to the value.
    110         */
    111        public static <T extends Comparable<T>> Predicate<T> gteq(final T value)
    112        {
    113            return new Predicate<T>()
    114            {
    115                public boolean accept(T element)
    116                {
    117                    return element.compareTo(value) >= 0;
    118                }
    119            };
    120        }
    121
    122        /**
    123         * A Predicate factory for comparison of a Comparable against a fixed value; true
    124         * if the element is less than the value.
    125         */
    126        public static <T extends Comparable<T>> Predicate<T> lt(T value)
    127        {
    128            return not(gteq(value));
    129        }
    130
    131        /**
    132         * A Predicate factory for comparison of a Comprable element against a fixed value; true
    133         * if the element is less than or equal to the value.
    134         */
    135        public static <T extends Comparable<T>> Predicate<T> lteq(T value)
    136        {
    137            return not(gt(value));
    138        }
    139
    140        /**
    141         * A Predicate factory; returns true if the value from the Flow is null.
    142         */
    143        public static <T> Predicate<T> isNull()
    144        {
    145            return new Predicate<T>()
    146            {
    147                public boolean accept(T element)
    148                {
    149                    return element == null;
    150                }
    151            };
    152        }
    153
    154        /**
    155         * A Predicate factory; returns true if the value from the Flow is not null.
    156         */
    157        public static <T> Predicate<T> notNull()
    158        {
    159            return not(isNull());
    160        }
    161
    162        /**
    163         * A Mapper factory that gets the string value of the flow value using {@link String#valueOf(Object)}.
    164         */
    165        public static <T> Mapper<T, String> stringValueOf()
    166        {
    167            return new Mapper<T, String>()
    168            {
    169                public String map(T value)
    170                {
    171                    return String.valueOf(value);
    172                }
    173            };
    174        }
    175
    176        /**
    177         * A Mapper factory; the returned Mapper ignores its input value and always returns a
    178         * predetermined result.
    179         */
    180        public static <S, T> Mapper<S, T> always(final T fixedResult)
    181        {
    182            return new Mapper<S, T>()
    183            {
    184                public T map(S input)
    185                {
    186                    return fixedResult;
    187                }
    188            };
    189        }
    190
    191        /**
    192         * A Mapper factory that combines a Predicate with two {@link Mapper}s; evaluating the predicate
    193         * selects one of the two mappers.
    194         *
    195         * @param predicate  evaluated to selected a coercion
    196         * @param ifAccepted used when predicate evaluates to true
    197         * @param ifRejected used when predicate evaluates to false
    198         */
    199        public static <S, T> Mapper<S, T> select(final Predicate<? super S> predicate, final Mapper<S, T> ifAccepted,
    200                                                 final Mapper<S, T> ifRejected)
    201        {
    202            assert predicate != null;
    203            assert ifAccepted != null;
    204            assert ifRejected != null;
    205
    206            return new Mapper<S, T>()
    207            {
    208                public T map(S input)
    209                {
    210                    Mapper<S, T> active = predicate.accept(input) ? ifAccepted : ifRejected;
    211
    212                    return active.map(input);
    213                }
    214            };
    215        }
    216
    217        /**
    218         * Override of {@link #select(Predicate, Mapper, Mapper)} where rejected values are replaced
    219         * with null.
    220         */
    221        public static <S, T> Mapper<S, T> select(Predicate<? super S> predicate, Mapper<S, T> ifAccepted)
    222        {
    223            return select(predicate, ifAccepted, (T) null);
    224        }
    225
    226        /**
    227         * Override of {@link #select(Predicate, Mapper)} where rejected values are replaced with a
    228         * fixed value.
    229         */
    230        public static <S, T> Mapper<S, T> select(Predicate<? super S> predicate, Mapper<S, T> ifAccepted, T ifRejectedValue)
    231        {
    232            Mapper<S, T> rejectedMapper = always(ifRejectedValue);
    233
    234            return select(predicate, ifAccepted, rejectedMapper);
    235        }
    236
    237        /**
    238         * A Mapper factory; the Mapper returns the the flow value unchanged.
    239         */
    240        public static <S> Mapper<S, S> identity()
    241        {
    242            return new Mapper<S, S>()
    243            {
    244                public S map(S input)
    245                {
    246                    return input;
    247                }
    248            };
    249        }
    250
    251        /**
    252         * Allows a Mapper that maps to boolean to be used as a Predicate.
    253         */
    254        public static <S> Predicate<S> toPredicate(final Mapper<S, Boolean> mapper)
    255        {
    256            assert mapper != null;
    257
    258            return new Predicate<S>()
    259            {
    260                public boolean accept(S object)
    261                {
    262                    return mapper.map(object);
    263                }
    264            };
    265        }
    266
    267        /**
    268         * A Reducer that operates on a Flow of Integers and is used to sum the values.
    269         */
    270        public static Reducer<Integer, Integer> SUM_INTS = new Reducer<Integer, Integer>()
    271        {
    272            public Integer reduce(Integer accumulator, Integer value)
    273            {
    274                return accumulator + value;
    275            }
    276        };
    277
    278        /**
    279         * A two-input Mapper used to add the values from two Flows of Integers into a Flow of Integer
    280         * sums.
    281         */
    282        public static Mapper2<Integer, Integer, Integer> ADD_INTS = new Mapper2<Integer, Integer, Integer>()
    283        {
    284            public Integer map(Integer first, Integer second)
    285            {
    286                return first + second;
    287            }
    288        };
    289
    290        /**
    291         * Extracts the values from the collection to form a {@link Flow}. The Collection
    292         * may change after the Flow is created without affecting the Flow.
    293         */
    294        public static <T> Flow<T> flow(Collection<T> values)
    295        {
    296            assert values != null;
    297
    298            if (values.isEmpty())
    299                return emptyFlow();
    300
    301            return new ArrayFlow<T>(values);
    302        }
    303
    304        /**
    305         * Creates a new Flow from the values. You should not change the values array
    306         * after invoking this method (i.e., no defensive copy of the values is made).
    307         */
    308        public static <T> Flow<T> flow(T... values)
    309        {
    310            if (values.length == 0)
    311                return emptyFlow();
    312
    313            return new ArrayFlow<T>(values);
    314        }
    315
    316        /**
    317         * Creates a lazy Flow from the {@link Iterator} obtained from the iterable. The Flow
    318         * will be threadsafe as long as the iterable yields a new Iterator on each invocation <em>and</em> the underlying
    319         * iterable object is not modified while the Flow is evaluating.
    320         * In other words, not extremely threadsafe.
    321         */
    322        public static <T> Flow<T> flow(Iterable<T> iterable)
    323        {
    324            assert iterable != null;
    325
    326            return flow(iterable.iterator());
    327        }
    328
    329        /**
    330         * Creates a lazy Flow from the {@link Iterator}. The Flow will be threadsafe as long as the underlying iterable
    331         * object is not modified while the Flow is evaluating. In other words, not extremely threadsafe.
    332         *
    333         * @since 5.3
    334         */
    335        public static <T> Flow<T> flow(Iterator<T> iterator)
    336        {
    337            return lazy(new LazyIterator<T>(iterator));
    338        }
    339
    340        /**
    341         * Creates a ZippedFlow from the provided map; the order of the tuples in the ZippedFlow is defined
    342         * by the iteration order of the map entries.
    343         *
    344         * @param <A> type of key and first tuple value
    345         * @param <B> type of value and second tuple value
    346         * @param map source of tuples
    347         * @return zipped flow created from map
    348         * @since 5.3
    349         */
    350        public static <A, B> ZippedFlow<A, B> zippedFlow(Map<A, B> map)
    351        {
    352            assert map != null;
    353
    354            Flow<Tuple<A, B>> tuples = F.flow(map.entrySet()).map(new Mapper<Map.Entry<A, B>, Tuple<A, B>>()
    355            {
    356                public Tuple<A, B> map(Entry<A, B> element)
    357                {
    358                    return Tuple.create(element.getKey(), element.getValue());
    359                }
    360            });
    361
    362            return ZippedFlowImpl.create(tuples);
    363        }
    364
    365        /**
    366         * Creates a lazy Flow that returns integers in the given range. The range starts
    367         * with the lower value and counts by 1 up to the upper range (which is not part of
    368         * the Flow). If lower equals upper, the Flow is empty. If upper is less than lower,
    369         * the Flow counts down instead.
    370         *
    371         * @param lower start of range (inclusive)
    372         * @param upper end of range (exclusive)
    373         */
    374        public static Flow<Integer> range(int lower, int upper)
    375        {
    376            if (lower == upper)
    377                return F.emptyFlow();
    378
    379            if (lower < upper)
    380                return lazy(new LazyRange(lower, upper, 1));
    381
    382            return lazy(new LazyRange(lower, upper, -1));
    383        }
    384
    385        /**
    386         * Creates a {@link Flow} from a {@linkplain LazyFunction lazy function}.
    387         */
    388        public static <T> Flow<T> lazy(LazyFunction<T> function)
    389        {
    390            assert function != null;
    391
    392            return new LazyFlow<T>(function);
    393        }
    394
    395        private static <T> LazyFunction<T> toLazyFunction(final T currentValue, final Mapper<T, T> function)
    396        {
    397            return new LazyFunction<T>()
    398            {
    399                public LazyContinuation<T> next()
    400                {
    401                    final T nextValue = function.map(currentValue);
    402
    403                    return new LazyContinuation<T>(nextValue, toLazyFunction(nextValue, function));
    404                }
    405            };
    406        }
    407
    408        /**
    409         * Creates an infinite lazy flow from an initial value and a function to map from the current value to the
    410         * next value.
    411         *
    412         * @param initial  initial value in flow
    413         * @param function maps from current value in flow to next value in flow
    414         * @return lazy flow
    415         */
    416        public static <T> Flow<T> iterate(final T initial, final Mapper<T, T> function)
    417        {
    418            LazyFunction<T> head = new LazyFunction<T>()
    419            {
    420                public LazyContinuation<T> next()
    421                {
    422                    return new LazyContinuation<T>(initial, toLazyFunction(initial, function));
    423                }
    424            };
    425
    426            return lazy(head);
    427        }
    428
    429        /**
    430         * Creates an <em>infinite</em> series of numbers.
    431         * <p/>
    432         * Attempting to get the {@linkplain Flow#count()} of the series will form an infinite loop.
    433         */
    434        public static Flow<Integer> series(int start, final int delta)
    435        {
    436            return iterate(start, new Mapper<Integer, Integer>()
    437            {
    438                public Integer map(Integer element)
    439                {
    440                    return element + delta;
    441                }
    442            });
    443        }
    444
    445        /**
    446         * A Worker factory; the returnedWorker adds the values to a provided collection.
    447         */
    448        public static <T> Worker<T> addToCollection(final Collection<T> coll)
    449        {
    450            return new Worker<T>()
    451            {
    452                public void work(T value)
    453                {
    454                    coll.add(value);
    455                }
    456            };
    457        }
    458
    459        /**
    460         * A Predicate factory for matching String elements with a given prefix.
    461         *
    462         * @since 5.3
    463         */
    464        public static Predicate<String> startsWith(String prefix)
    465        {
    466            return startsWith(prefix, false);
    467        }
    468
    469        /**
    470         * As {@link #startsWith(String)}, but ignores case.
    471         *
    472         * @since 5.3
    473         */
    474        public static Predicate<String> startsWithIgnoringCase(String prefix)
    475        {
    476            return startsWith(prefix, true);
    477        }
    478
    479        /**
    480         * @since 5.3
    481         */
    482        private static Predicate<String> startsWith(final String prefix, final boolean ignoreCase)
    483        {
    484            return new Predicate<String>()
    485            {
    486                public boolean accept(String element)
    487                {
    488                    return element.regionMatches(ignoreCase, 0, prefix, 0, prefix.length());
    489                }
    490            };
    491        }
    492
    493        /**
    494         * A Predicate factory for matching String elements with a given suffix.
    495         *
    496         * @since 5.3
    497         */
    498        public static Predicate<String> endsWith(String suffix)
    499        {
    500            return endsWith(suffix, false);
    501        }
    502
    503        /**
    504         * As with {@link #endsWith(String)} but ignores case.
    505         *
    506         * @since 5.3
    507         */
    508        public static Predicate<String> endsWithIgnoringCase(String suffix)
    509        {
    510            return endsWith(suffix, true);
    511        }
    512
    513        /**
    514         * @since 5.3
    515         */
    516        private static Predicate<String> endsWith(final String suffix, final boolean ignoreCase)
    517        {
    518            return new Predicate<String>()
    519            {
    520                public boolean accept(String element)
    521                {
    522                    return element
    523                            .regionMatches(ignoreCase, element.length() - suffix.length(), suffix, 0, suffix.length());
    524                }
    525            };
    526        }
    527
    528        /**
    529         * Creates a Comparator for the Tuples of a {@link ZippedFlow} that sorts the Tuple elements based on the first
    530         * value in the Tuple.
    531         *
    532         * @since 5.3
    533         */
    534        public static <A extends Comparable<A>, B> Comparator<Tuple<A, B>> orderByFirst()
    535        {
    536            return new Comparator<Tuple<A, B>>()
    537            {
    538                public int compare(Tuple<A, B> o1, Tuple<A, B> o2)
    539                {
    540                    return o1.first.compareTo(o2.first);
    541                }
    542            };
    543        }
    544
    545        /**
    546         * Creates a Comparator for the Tuples of a {@link ZippedFlow} that sorts the Tuple elements based on the first
    547         * value in the Tuple.
    548         *
    549         * @since 5.3
    550         */
    551        public static <A, B extends Comparable<B>> Comparator<Tuple<A, B>> orderBySecond()
    552        {
    553            return new Comparator<Tuple<A, B>>()
    554            {
    555                public int compare(Tuple<A, B> o1, Tuple<A, B> o2)
    556                {
    557                    return o1.second.compareTo(o2.second);
    558                }
    559            };
    560        }
    561
    562        /**
    563         * Inverts a predicate.
    564         *
    565         * @param delegate the predicate to invert
    566         * @return a new predicate that is inverse to the existing predicate
    567         * @since 5.3
    568         */
    569        public static <T> Predicate<T> not(final Predicate<? super T> delegate)
    570        {
    571            assert delegate != null;
    572
    573            return new Predicate<T>()
    574            {
    575                public boolean accept(T element)
    576                {
    577                    return !delegate.accept(element);
    578                }
    579            };
    580        }
    581
    582        /**
    583         * Combines two mappers into a composite mapping from type A to type C via type B.
    584         *
    585         * @param abMapper maps from A to B
    586         * @param bcMapper maps from B to C
    587         * @return mapper from A to C
    588         */
    589        public static <A, B, C> Mapper<A, C> combine(final Mapper<A, B> abMapper, final Mapper<B, C> bcMapper)
    590        {
    591            assert abMapper != null;
    592            assert bcMapper != null;
    593
    594            return new Mapper<A, C>()
    595            {
    596
    597                public C map(A aElement)
    598                {
    599                    B bElement = abMapper.map(aElement);
    600
    601                    return bcMapper.map(bElement);
    602                }
    603
    604            };
    605        }
    606
    607        /**
    608         * Combines any number of delegates as a logical and operation. Evaluation terminates
    609         * with the first delegate predicate that returns false.
    610         *
    611         * @param delegates to evaluate
    612         * @return combined delegate
    613         * @since 5.3
    614         */
    615        public static <T> Predicate<T> and(final Predicate<? super T>... delegates)
    616        {
    617            return new Predicate<T>()
    618            {
    619                public boolean accept(T element)
    620                {
    621                    for (Predicate<? super T> delegate : delegates)
    622                    {
    623                        if (!delegate.accept(element))
    624                            return false;
    625                    }
    626
    627                    return true;
    628                }
    629            };
    630        }
    631
    632        /**
    633         * Combines any number of delegates as a logical or operation. Evaluation terminates
    634         * with the first delegate predicate that returns true.
    635         *
    636         * @param delegates to evaluate
    637         * @return combined delegate
    638         * @since 5.3
    639         */
    640        public static <T> Predicate<T> or(final Predicate<? super T>... delegates)
    641        {
    642            return new Predicate<T>()
    643            {
    644                public boolean accept(T element)
    645                {
    646                    for (Predicate<? super T> delegate : delegates)
    647                    {
    648                        if (delegate.accept(element))
    649                            return true;
    650                    }
    651
    652                    return false;
    653                }
    654            };
    655        }
    656
    657        /**
    658         * Combines several compatible workers together into a composite.
    659         *
    660         * @since 5.3
    661         */
    662        public static <T> Worker<T> combine(final Worker<? super T>... delegates)
    663        {
    664            assert delegates.length > 0;
    665
    666            return new Worker<T>()
    667            {
    668                public void work(T value)
    669                {
    670                    for (Worker<? super T> delegate : delegates)
    671                    {
    672                        delegate.work(value);
    673                    }
    674                }
    675            };
    676        }
    677    }