View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections.functors;
18  
19  import java.io.Serializable;
20  import java.util.Map;
21  
22  import org.apache.commons.collections.Predicate;
23  import org.apache.commons.collections.Transformer;
24  
25  /**
26   * Transformer implementation calls the transformer whose predicate returns true,
27   * like a switch statement.
28   *
29   * @since 3.0
30   * @version $Id: SwitchTransformer.java 1437000 2013-01-22 15:39:58Z tn $
31   */
32  public class SwitchTransformer<I, O> implements Transformer<I, O>, Serializable {
33  
34      /** Serial version UID */
35      private static final long serialVersionUID = -6404460890903469332L;
36  
37      /** The tests to consider */
38      private final Predicate<? super I>[] iPredicates;
39      /** The matching transformers to call */
40      private final Transformer<? super I, ? extends O>[] iTransformers;
41      /** The default transformer to call if no tests match */
42      private final Transformer<? super I, ? extends O> iDefault;
43  
44      /**
45       * Factory method that performs validation and copies the parameter arrays.
46       * 
47       * @param <I>  the input type
48       * @param <O>  the output type
49       * @param predicates  array of predicates, cloned, no nulls
50       * @param transformers  matching array of transformers, cloned, no nulls
51       * @param defaultTransformer  the transformer to use if no match, null means return null
52       * @return the <code>chained</code> transformer
53       * @throws IllegalArgumentException if array is null
54       * @throws IllegalArgumentException if any element in the array is null
55       */
56      @SuppressWarnings("unchecked")
57      public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates,
58              final Transformer<? super I, ? extends O>[] transformers,
59              final Transformer<? super I, ? extends O> defaultTransformer) {
60          FunctorUtils.validate(predicates);
61          FunctorUtils.validate(transformers);
62          if (predicates.length != transformers.length) {
63              throw new IllegalArgumentException("The predicate and transformer arrays must be the same size");
64          }
65          if (predicates.length == 0) {
66              return (Transformer<I, O>) (defaultTransformer == null ? ConstantTransformer.<I, O>nullTransformer() :
67                                                                       defaultTransformer);
68          }
69          return new SwitchTransformer<I, O>(FunctorUtils.copy(predicates),
70                                             FunctorUtils.copy(transformers),
71                                             defaultTransformer);
72      }
73  
74      /**
75       * Create a new Transformer that calls one of the transformers depending 
76       * on the predicates. 
77       * <p>
78       * The Map consists of Predicate keys and Transformer values. A transformer 
79       * is called if its matching predicate returns true. Each predicate is evaluated
80       * until one returns true. If no predicates evaluate to true, the default
81       * transformer is called. The default transformer is set in the map with a 
82       * null key. The ordering is that of the iterator() method on the entryset 
83       * collection of the map.
84       * 
85       * @param <I>  the input type
86       * @param <O>  the output type
87       * @param map  a map of predicates to transformers
88       * @return the <code>switch</code> transformer
89       * @throws IllegalArgumentException if the map is null
90       * @throws IllegalArgumentException if any transformer in the map is null
91       * @throws ClassCastException  if the map elements are of the wrong type
92       */
93      @SuppressWarnings("unchecked")
94      public static <I, O> Transformer<I, O> switchTransformer(
95              final Map<? extends Predicate<? super I>, ? extends Transformer<? super I, ? extends O>> map) {
96  
97          if (map == null) {
98              throw new IllegalArgumentException("The predicate and transformer map must not be null");
99          }
100         if (map.size() == 0) {
101             return ConstantTransformer.<I, O>nullTransformer();
102         }
103         // convert to array like this to guarantee iterator() ordering
104         final Transformer<? super I, ? extends O> defaultTransformer = map.remove(null);
105         final int size = map.size();
106         if (size == 0) {
107             return (Transformer<I, O>) (defaultTransformer == null ? ConstantTransformer.<I, O>nullTransformer() :
108                                                                      defaultTransformer);
109         }
110         final Transformer<? super I, ? extends O>[] transformers = new Transformer[size];
111         final Predicate<? super I>[] preds = new Predicate[size];
112         int i = 0;
113         for (final Map.Entry<? extends Predicate<? super I>,
114                              ? extends Transformer<? super I, ? extends O>> entry : map.entrySet()) {
115             preds[i] = entry.getKey();
116             transformers[i] = entry.getValue();
117             i++;
118         }
119         return new SwitchTransformer<I, O>(preds, transformers, defaultTransformer);
120     }
121     
122     /**
123      * Constructor that performs no validation.
124      * Use <code>getInstance</code> if you want that.
125      * 
126      * @param predicates  array of predicates, not cloned, no nulls
127      * @param transformers  matching array of transformers, not cloned, no nulls
128      * @param defaultTransformer  the transformer to use if no match, null means return null
129      */
130     @SuppressWarnings("unchecked")
131     public SwitchTransformer(final Predicate<? super I>[] predicates,
132             final Transformer<? super I, ? extends O>[] transformers,
133             final Transformer<? super I, ? extends O> defaultTransformer) {
134         super();
135         iPredicates = predicates;
136         iTransformers = transformers;
137         iDefault = (Transformer<? super I, ? extends O>) (defaultTransformer == null ?
138                 ConstantTransformer.<I, O>nullTransformer() : defaultTransformer);
139     }
140 
141     /**
142      * Transforms the input to result by calling the transformer whose matching
143      * predicate returns true.
144      * 
145      * @param input  the input object to transform
146      * @return the transformed result
147      */
148     public O transform(final I input) {
149         for (int i = 0; i < iPredicates.length; i++) {
150             if (iPredicates[i].evaluate(input) == true) {
151                 return iTransformers[i].transform(input);
152             }
153         }
154         return iDefault.transform(input);
155     }
156 
157     /**
158      * Gets the predicates.
159      * 
160      * @return a copy of the predicates
161      * @since 3.1
162      */
163     public Predicate<? super I>[] getPredicates() {
164         return FunctorUtils.<I>copy(iPredicates);
165     }
166 
167     /**
168      * Gets the transformers.
169      * 
170      * @return a copy of the transformers
171      * @since 3.1
172      */
173     public Transformer<? super I, ? extends O>[] getTransformers() {
174         return FunctorUtils.<I, O>copy(iTransformers);
175     }
176 
177     /**
178      * Gets the default transformer.
179      * 
180      * @return the default transformer
181      * @since 3.1
182      */
183     public Transformer<? super I, ? extends O> getDefaultTransformer() {
184         return iDefault;
185     }
186 
187 }