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 */ 017 package org.apache.commons.collections.functors; 018 019 import java.io.Serializable; 020 import java.util.Iterator; 021 import java.util.Map; 022 023 import org.apache.commons.collections.Predicate; 024 import org.apache.commons.collections.Transformer; 025 026 /** 027 * Transformer implementation calls the transformer whose predicate returns true, 028 * like a switch statement. 029 * 030 * @since Commons Collections 3.0 031 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $ 032 * 033 * @author Stephen Colebourne 034 */ 035 public class SwitchTransformer implements Transformer, Serializable { 036 037 /** Serial version UID */ 038 private static final long serialVersionUID = -6404460890903469332L; 039 040 /** The tests to consider */ 041 private final Predicate[] iPredicates; 042 /** The matching transformers to call */ 043 private final Transformer[] iTransformers; 044 /** The default transformer to call if no tests match */ 045 private final Transformer iDefault; 046 047 /** 048 * Factory method that performs validation and copies the parameter arrays. 049 * 050 * @param predicates array of predicates, cloned, no nulls 051 * @param transformers matching array of transformers, cloned, no nulls 052 * @param defaultTransformer the transformer to use if no match, null means return null 053 * @return the <code>chained</code> transformer 054 * @throws IllegalArgumentException if array is null 055 * @throws IllegalArgumentException if any element in the array is null 056 */ 057 public static Transformer getInstance(Predicate[] predicates, Transformer[] transformers, Transformer defaultTransformer) { 058 FunctorUtils.validate(predicates); 059 FunctorUtils.validate(transformers); 060 if (predicates.length != transformers.length) { 061 throw new IllegalArgumentException("The predicate and transformer arrays must be the same size"); 062 } 063 if (predicates.length == 0) { 064 return (defaultTransformer == null ? ConstantTransformer.NULL_INSTANCE : defaultTransformer); 065 } 066 predicates = FunctorUtils.copy(predicates); 067 transformers = FunctorUtils.copy(transformers); 068 return new SwitchTransformer(predicates, transformers, defaultTransformer); 069 } 070 071 /** 072 * Create a new Transformer that calls one of the transformers depending 073 * on the predicates. 074 * <p> 075 * The Map consists of Predicate keys and Transformer values. A transformer 076 * is called if its matching predicate returns true. Each predicate is evaluated 077 * until one returns true. If no predicates evaluate to true, the default 078 * transformer is called. The default transformer is set in the map with a 079 * null key. The ordering is that of the iterator() method on the entryset 080 * collection of the map. 081 * 082 * @param predicatesAndTransformers a map of predicates to transformers 083 * @return the <code>switch</code> transformer 084 * @throws IllegalArgumentException if the map is null 085 * @throws IllegalArgumentException if any transformer in the map is null 086 * @throws ClassCastException if the map elements are of the wrong type 087 */ 088 public static Transformer getInstance(Map predicatesAndTransformers) { 089 Transformer[] transformers = null; 090 Predicate[] preds = null; 091 if (predicatesAndTransformers == null) { 092 throw new IllegalArgumentException("The predicate and transformer map must not be null"); 093 } 094 if (predicatesAndTransformers.size() == 0) { 095 return ConstantTransformer.NULL_INSTANCE; 096 } 097 // convert to array like this to guarantee iterator() ordering 098 Transformer defaultTransformer = (Transformer) predicatesAndTransformers.remove(null); 099 int size = predicatesAndTransformers.size(); 100 if (size == 0) { 101 return (defaultTransformer == null ? ConstantTransformer.NULL_INSTANCE : defaultTransformer); 102 } 103 transformers = new Transformer[size]; 104 preds = new Predicate[size]; 105 int i = 0; 106 for (Iterator it = predicatesAndTransformers.entrySet().iterator(); it.hasNext();) { 107 Map.Entry entry = (Map.Entry) it.next(); 108 preds[i] = (Predicate) entry.getKey(); 109 transformers[i] = (Transformer) entry.getValue(); 110 i++; 111 } 112 return new SwitchTransformer(preds, transformers, defaultTransformer); 113 } 114 115 /** 116 * Constructor that performs no validation. 117 * Use <code>getInstance</code> if you want that. 118 * 119 * @param predicates array of predicates, not cloned, no nulls 120 * @param transformers matching array of transformers, not cloned, no nulls 121 * @param defaultTransformer the transformer to use if no match, null means return null 122 */ 123 public SwitchTransformer(Predicate[] predicates, Transformer[] transformers, Transformer defaultTransformer) { 124 super(); 125 iPredicates = predicates; 126 iTransformers = transformers; 127 iDefault = (defaultTransformer == null ? ConstantTransformer.NULL_INSTANCE : defaultTransformer); 128 } 129 130 /** 131 * Transforms the input to result by calling the transformer whose matching 132 * predicate returns true. 133 * 134 * @param input the input object to transform 135 * @return the transformed result 136 */ 137 public Object transform(Object input) { 138 for (int i = 0; i < iPredicates.length; i++) { 139 if (iPredicates[i].evaluate(input) == true) { 140 return iTransformers[i].transform(input); 141 } 142 } 143 return iDefault.transform(input); 144 } 145 146 /** 147 * Gets the predicates, do not modify the array. 148 * 149 * @return the predicates 150 * @since Commons Collections 3.1 151 */ 152 public Predicate[] getPredicates() { 153 return iPredicates; 154 } 155 156 /** 157 * Gets the transformers, do not modify the array. 158 * 159 * @return the transformers 160 * @since Commons Collections 3.1 161 */ 162 public Transformer[] getTransformers() { 163 return iTransformers; 164 } 165 166 /** 167 * Gets the default transformer. 168 * 169 * @return the default transformer 170 * @since Commons Collections 3.1 171 */ 172 public Transformer getDefaultTransformer() { 173 return iDefault; 174 } 175 176 }