View Javadoc

1   /* Copyright (c) 2008 Sascha Kohlmann
2    *
3    * This program is free software: you can redistribute it and/or modify
4    * it under the terms of the GNU Affero General Public License as published by
5    * the Free Software Foundation, either version 3 of the License, or
6    * (at your option) any later version.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Affero General Public License for more details.
12   *
13   * You should have received a copy of the GNU Affero General Public License
14   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15   */
16  package net.sf.eos.util;
17  
18  import net.sf.eos.Experimental;
19  import net.sf.eos.Function;
20  import net.sf.eos.Predicate;
21  import net.sf.eos.Supplier;
22  import static net.sf.eos.util.Conditions.checkArgumentNotNull;
23  
24  /**
25   * Defines some useful compositions for handling with {@link Function Functions},
26   * {@link Predicate Predicates} and {@link Supplier Suppliers}.
27   *
28   * <p>Each {@code composition} follows the rule of a {@code from} or <em>source</em>
29   * entity, propagating its result value to a {@code to} or <em>target</em> entity.</p>
30   *
31   * @author Sascha Kohlmann
32   */
33  @Experimental
34  public class Compositions {
35  
36      /**
37       * Returns the composition of two functions. For {@code f: F→I} and
38       * {@code g: I→T}, composition is defined as the function {@code h}
39       * such that {@code h(x) == g(f(x))} for each {@code x}.
40       *
41       * <p>The usage interface is designed as a {@code from} function which
42       * propagates its result to the {@code to} function.</p>
43       *
44       * @param <F> the {@code from} or <em>source</em> type
45       * @param <I> the intermediate type
46       * @param <T> the {@code to} or <em>target</em> type
47       * @param from the {@code from} or <em>source</em> {@code function}
48       * @param to the {@code to} or <em>target</em> {@code function}
49       * @throws IllegalArgumentException if one parameter is {@code null}
50       * @since 0.1.0
51       */
52      public final static <F, I, T> Function<F, T> compose(
53              final Function<? super F, ? extends I> from,
54              final Function<? super I, ? extends T> to) {
55          return new FunctionComposition<F, I, T>(from, to);
56      }
57  
58      /**
59       * @see #compose(Function, Function)
60       */
61      private final static class FunctionComposition<F, I, T> implements Function<F, T> {
62  
63          private final Function<? super F, ? extends I> from;
64          private final Function<? super I, ? extends T> to;
65          
66          public FunctionComposition(final Function<? super F, ? extends I> from,
67                                     final Function<? super I, ? extends T> to) {
68              this.from = checkArgumentNotNull(from, "from is null");
69              this.to = checkArgumentNotNull(to, "to is null");
70          }
71          public T apply(final F source) {
72                return to.apply(from.apply(source));
73              }
74      }
75  
76      /**
77       * Returns a composition of a <em>from</em> {@code Function} and an evaluating
78       * <em>to</em> {@code Predicate}. The {@code predicate} retrieves the value from
79       * the {@code function}.
80       *
81       * <p>The usage interface is designed as a {@code from} function which
82       * propagates its result to the {@code to} predicate.</p>
83       *
84       * @param <F> the {@code from} or <em>source</em> type
85       * @param <T> the {@code to} or <em>target</em> type
86       * @param fromFunction the {@code from} or <em>source</em> {@code function}
87       * @param toPredicate the {@code to} or <em>target</em> {@code predicate}
88       * @return a {@code predicate}
89       * @throws IllegalArgumentException if one parameter is {@code null}
90       * @since 0.7.0
91       */
92      public final static <F, T> Predicate<F> compose(
93              final Function<? super F, ? extends T> fromFunction,
94              final Predicate<T> toPredicate) {
95          return new FunctionPredicateComposition<F, T>(fromFunction, toPredicate);
96      }
97  
98      /** @see #compose(Function, Predicate) */
99      private final static class FunctionPredicateComposition<F, T>
100             implements Predicate<F> {
101 
102         private final Predicate<? super T> to;
103         private final Function<? super F, ? extends T> from;
104 
105         /**
106          * Constructs the composition of the given {@code Function} and
107          * {@code Predicate}.
108          *
109          * @param fromFunction the inner {@link Function}. Must not be {@code null}.
110          * @param toPredicate the outer {@link Predicate}. Must not be {@code null}.
111          */
112         @SuppressWarnings("nls")
113         public FunctionPredicateComposition(
114                 final Function<? super F, ? extends T> fromFunction,
115                 final Predicate<T> toPredicate) {
116           this.from = checkArgumentNotNull(fromFunction, "fromFunction is null");
117           this.to = checkArgumentNotNull(toPredicate, "toPredicate is null");
118         }
119 
120         /** {@inheritDoc} */
121         public boolean evaluate(final F source) {
122             return this.to.evaluate(this.from.apply(source));
123         }
124     }
125     
126     /**
127      * Returns a composition of a <em>from</em> {@code Supplier} and an applied
128      * <em>to</em> {@code Function}. The {@code function} retrieves the value from
129      * the {@code supplier}.
130      *
131      * <p>The usage interface is designed as a {@code from} supplier which
132      * propagates its result to the {@code to} function.</p>
133      *
134      * @param <F> the {@code from} or <em>source</em> type
135      * @param <T> the {@code to} or <em>target</em> type
136      * @param fromSupplier the {@code from} or <em>source</em> {@code supplier}
137      * @param toFunction the {@code to} or <em>target</em> {@code function}
138      * @return a {@code supplier} with the value from {@code function}
139      * @throws IllegalArgumentException if one parameter is {@code null}
140      * @since 0.7.0
141      */
142     public final static <F, T> Supplier<T> compose(
143             final Supplier<? extends F> fromSupplier,
144             final Function<F, T> toFunction) {
145         return new SupplierFunctionComposition<F, T>(fromSupplier, toFunction);
146     }
147 
148     /** @see #compose(Supplier, Function) */
149     private final static class SupplierFunctionComposition<F, T>
150             implements Supplier<T> {
151 
152         private final Supplier<? extends F> from;
153         private final Function<? super F, ? extends T> to;
154 
155         /**
156          * Constructs the composition of the given {@code Supplier} and
157          * {@code Function}.
158          *
159          * @param fromSupplier the inner {@link Supplier}. Must not be {@code null}.
160          * @param toFunction the outer {@link Function}. Must not be {@code null}.
161          */
162         @SuppressWarnings("nls")
163         public SupplierFunctionComposition(final Supplier<? extends F> fromSupplier,
164                                            final Function<F, T> toFunction) {
165           this.from = checkArgumentNotNull(fromSupplier, "fromSupplier is null");
166           this.to = checkArgumentNotNull(toFunction, "toFunction is null");
167         }
168 
169         /** {@inheritDoc} */
170         public T get() {
171           return this.to.apply(this.from.get());
172         }
173     }
174 
175     /**
176      * Composes a rule. A rule contains a {@code predicate} as decision maker either to call the
177      * {@code trueFunction} or the {@code falseFunction}. The returning function calls the 
178      * {@code trueFunction} if {@code predicate} returns {@code true}. Otherwise the
179      * {@code falseFunction} will call.
180      * @param <F> the input type of the {@code predicate} and the {@code functions}
181      * @param <T> the output type of the applyied {@code functions}
182      * @param decider the decision maker
183      * @param trueFunction apply if the decision maker returns {@code true}
184      * @param falseFunction apply if the decision maker returns {@code false}
185      * @return a ruling function
186      * @since 0.8.1
187      */
188     public final static <F, T> Function<F, T> composeRule(
189             final Predicate<? super F> decider,
190             final Function<? super F, ? extends T> trueFunction,
191             final Function<? super F, ? extends T> falseFunction) {
192         return new RuledFunctionComposition<F, T>(decider, trueFunction, falseFunction);
193     }
194 
195     /** @see #compose(Predicate, Function, Function) */
196     private static class RuledFunctionComposition<F, T> implements Function<F, T> {
197         /** The <em>trueFunction</em> will aplly if {@link #decisionMaker} returns {@code true}. */
198         private final Function<? super F, ? extends T> trueFunction;
199 
200         /** The <em>falseFunction</em> will aplly if {@link #decisionMaker} returns {@code false}. */
201         private final Function<? super F, ? extends T> falseFunction;
202 
203         /** Descider either call <em>trueFunction</em> or <em>falseFunction</em>. */
204         private final Predicate<? super F> decisionMaker;
205 
206         /**
207          * Constructs the composition of the given {@link Predicate} and {@link Function Functions}.
208          *
209          * @param decisionMaker the predicate which decision is the source for using the
210          *                      <em>trueFunction</em> or the <em>falseFunction</em>
211          * @param trueFunction the {@link Function} will call if {@code decisionMaker}
212          *                     returns {@code true}
213          * @param falseFunction the {@link Function} will call if {@code decisionMaker}
214          *                      returns {@code false}
215          */
216         @SuppressWarnings("nls")
217         public RuledFunctionComposition(
218                 @SuppressWarnings("hiding") final Predicate<? super F> decisionMaker,
219                 @SuppressWarnings("hiding") final Function<? super F, ? extends T> trueFunction,
220                 @SuppressWarnings("hiding") final Function<? super F, ? extends T> falseFunction) {
221             this.decisionMaker = checkArgumentNotNull(decisionMaker, "decisionMaker is null");
222             this.trueFunction = checkArgumentNotNull(trueFunction, "trueFunction is null");
223             this.falseFunction = checkArgumentNotNull(falseFunction, "falseFunction is null");
224         }
225 
226         /** {@inheritDoc} */
227         public T apply(final F source) {
228             if (this.decisionMaker.evaluate(source)) { 
229                 return this.trueFunction.apply(source);
230             }
231             return this.falseFunction.apply(source);
232         }
233     }
234 
235     /** Never used. */
236     private Compositions() { }
237 }