View Javadoc

1   /*
2    * Copyright 2007-2008 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at
7    * 
8    * http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  package net.sf.morph.transform.copiers;
17  
18  import java.util.Arrays;
19  import java.util.Locale;
20  import java.util.Set;
21  
22  import net.sf.morph.transform.Converter;
23  import net.sf.morph.transform.DecoratedConverter;
24  import net.sf.morph.transform.DecoratedCopier;
25  import net.sf.morph.transform.ExplicitTransformer;
26  import net.sf.morph.transform.TransformationException;
27  import net.sf.morph.transform.Transformer;
28  import net.sf.morph.transform.converters.DefaultToBooleanConverter;
29  import net.sf.morph.transform.transformers.BaseTransformer;
30  import net.sf.morph.util.Assert;
31  import net.sf.morph.util.ClassUtils;
32  import net.sf.morph.util.ContainerUtils;
33  import net.sf.morph.util.TransformerUtils;
34  
35  /**
36   * This copier uses an <code>if</code> <code>Converter</code> to convert an incoming object to a Boolean.
37   * If this results in a Boolean object corresponding to boolean true, the then
38   * Transformer is invoked; otherwise the optional else Transformer is invoked if present. 
39   *
40   * @author Matt Benson
41   * @since Morph 1.1
42   */
43  public class ConditionalCopier extends BaseTransformer implements DecoratedConverter,
44  		DecoratedCopier, ExplicitTransformer {
45  	private static final Converter DEFAULT_IF = new DefaultToBooleanConverter();
46  
47  	private Converter ifConverter;
48  	private Transformer thenTransformer;
49  	private Transformer elseTransformer;
50  
51  	/**
52  	 * {@inheritDoc}
53  	 */
54  	protected Class[] getDestinationClassesImpl() throws Exception {
55  		Transformer tt = getThenTransformer();
56  		Transformer et = getElseTransformer();
57  		return et == null ? tt.getDestinationClasses() : tt == null ? et
58  				.getDestinationClasses() : merge(tt.getDestinationClasses(), et
59  				.getDestinationClasses());
60  	}
61  
62  	/**
63  	 * {@inheritDoc}
64  	 */
65  	protected Class[] getSourceClassesImpl() throws Exception {
66  		Transformer tt = getThenTransformer();
67  		Transformer et = getElseTransformer();
68  		return et == null ? tt.getSourceClasses() : tt == null ? et.getSourceClasses()
69  				: merge(tt.getSourceClasses(), et.getSourceClasses());
70  	}
71  
72  	/**
73  	 * {@inheritDoc}
74  	 */
75  	protected boolean isAutomaticallyHandlingNulls() {
76  		return false;
77  	}
78  
79  	/**
80  	 * {@inheritDoc}
81  	 */
82  	protected boolean isTransformableImpl(Class destinationType, Class sourceType)
83  			throws Exception {
84  		return TransformerUtils.isTransformable(getIfConverter(), Boolean.class,
85  				sourceType)
86  				&& (TransformerUtils.isTransformable(getThenTransformer(),
87  						destinationType, sourceType) || TransformerUtils.isTransformable(
88  						getElseTransformer(), destinationType, sourceType));
89  	}
90  
91  	/**
92  	 * {@inheritDoc}
93  	 */
94  	public synchronized void setDestinationClasses(Class[] destinationClasses) {
95  		super.setDestinationClasses(destinationClasses);
96  	}
97  
98  	/**
99  	 * {@inheritDoc}
100 	 */
101 	public synchronized void setSourceClasses(Class[] sourceClasses) {
102 		super.setSourceClasses(sourceClasses);
103 	}
104 
105 	/**
106 	 * {@inheritDoc}
107 	 */
108 	protected Object convertImpl(Class destinationClass, Object source, Locale locale)
109 			throws Exception {
110 		//pass source as default result when "if" fails and no "else":
111 		return transform(destinationClass, source, source, locale,
112 				TRANSFORMATION_TYPE_CONVERT);
113 	}
114 
115 	/**
116 	 * {@inheritDoc}
117 	 */
118 	protected void copyImpl(Object destination, Object source, Locale locale,
119 			Integer preferredTransformationType) throws Exception {
120 		transform(ClassUtils.getClass(destination), destination, source, locale,
121 				TRANSFORMATION_TYPE_COPY);
122 	}
123 
124 	/**
125 	 * Do the transformation.
126 	 * @param destinationType
127 	 * @param destination
128 	 * @param source
129 	 * @param locale
130 	 * @param preferredTransformationType
131 	 * @return
132 	 * @throws TransformationException
133 	 */
134 	protected Object transform(Class destinationType, Object destination, Object source,
135 			Locale locale, Integer preferredTransformationType)
136 			throws TransformationException {
137 		Transformer t;
138 		if (evaluateIf(source, locale)) {
139 			t = getThenTransformer();
140 			//note that the thenTransformer is not required until it is intended to be used
141 			Assert.notNull(t, "thenTransformer");
142 		}
143 		else {
144 			t = getElseTransformer();
145 		}
146 		return t == null ? destination : TransformerUtils.transform(t, destinationType,
147 				destination, source, locale, preferredTransformationType);
148 	}
149 
150 	/**
151 	 * Evaluate the source object against the ifConverter.
152 	 * @param source
153 	 * @param locale
154 	 * @return boolean result
155 	 */
156 	private boolean evaluateIf(Object source, Locale locale) {
157 		Boolean b = (Boolean) getIfConverter().convert(Boolean.class, source, locale);
158 		return Boolean.TRUE.equals(b);
159 	}
160 
161 	/**
162 	 * Get the ifConverter.
163 	 * @return Converter.
164 	 */
165 	public Converter getIfConverter() {
166 		return ifConverter == null ? DEFAULT_IF : ifConverter;
167 	}
168 
169 	/**
170 	 * Set the ifConverter. By default it will be an instance of {@link DefaultToBooleanConverter}.
171 	 * @param ifConverter the Converter ifConverter to set.
172 	 */
173 	public void setIfConverter(Converter ifConverter) {
174 		this.ifConverter = ifConverter;
175 	}
176 
177 	/**
178 	 * Get the thenTransformer.
179 	 * @return Transformer.
180 	 */
181 	public Transformer getThenTransformer() {
182 		return thenTransformer;
183 	}
184 
185 	/**
186 	 * Set the thenTransformer.
187 	 * @param thenTransformer the Transformer thenTransformer to set.
188 	 */
189 	public void setThenTransformer(Transformer thenTransformer) {
190 		this.thenTransformer = thenTransformer;
191 		setInitialized(false);
192 	}
193 
194 	/**
195 	 * Get the elseTransformer.
196 	 * @return Transformer.
197 	 */
198 	public Transformer getElseTransformer() {
199 		return elseTransformer;
200 	}
201 
202 	/**
203 	 * Set the elseTransformer.
204 	 * @param elseTransformer the Transformer elseTransformer to set.
205 	 */
206 	public void setElseTransformer(Transformer elseTransformer) {
207 		this.elseTransformer = elseTransformer;
208 		setInitialized(false);
209 	}
210 
211 	/**
212 	 * Merge two Class[]s.
213 	 * @param a
214 	 * @param b
215 	 * @return Class[]
216 	 */
217 	private static Class[] merge(Class[] a, Class[] b) {
218 		Set s = ContainerUtils.createOrderedSet();
219 		s.addAll(Arrays.asList(a));
220 		s.addAll(Arrays.asList(b));
221 		return (Class[]) s.toArray(new Class[s.size()]);
222 	}
223 
224 }
225