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.Iterator;
19  import java.util.Locale;
20  import java.util.NoSuchElementException;
21  
22  import net.sf.morph.reflect.IndexedContainerReflector;
23  import net.sf.morph.reflect.SizableReflector;
24  import net.sf.morph.transform.Converter;
25  import net.sf.morph.transform.DecoratedConverter;
26  import net.sf.morph.transform.DecoratedCopier;
27  import net.sf.morph.transform.TransformationException;
28  import net.sf.morph.transform.Transformer;
29  import net.sf.morph.util.ClassUtils;
30  import net.sf.morph.util.TransformerUtils;
31  
32  /**
33   * A copier that copies a source to multiple destination objects, implementing a "Disassembler."
34   *
35   * @see http://www.martinfowler.com/eaaCatalog/dataTransferObject.html
36   *
37   * @author Matt Benson
38   * @since Morph 1.1
39   */
40  public class DisassemblerCopier extends AssemblyCopierSupport implements DecoratedCopier,
41  		DecoratedConverter {
42  
43  	/**
44  	 * Adds the index to the source object to pass to the classConverter;
45  	 */
46  	public static class Disassembly {
47  		private Object source;
48  		private int index;
49  
50  		private Disassembly(Object source) {
51  			this.source = source;
52  		}
53  
54  		/**
55  		 * Get the source object
56  		 * @return Object
57  		 */
58  		public Object getSource() {
59  			return source;
60  		}
61  
62  		/**
63  		 * Get the current index.
64  		 * @return int index
65  		 */
66  		public int getIndex() {
67  			return index;
68  		}
69  
70  	}
71  
72  	private static class DisassemblyIterator implements Iterator {
73  		private Disassembly disassembly;
74  		private int size;
75  		private int index;
76  
77  		private DisassemblyIterator(Object source, int size) {
78  			this.disassembly = new Disassembly(source);
79  			this.size = size;
80  		}
81  
82  		public synchronized boolean hasNext() {
83  			return index < size;
84  		}
85  
86  		public synchronized Object next() {
87  			if (!hasNext()) {
88  				throw new NoSuchElementException();
89  			}
90  			try {
91  				disassembly.index = index;
92  				return disassembly;
93  			} finally {
94  				index++;
95  			}
96  		}
97  
98  		public void remove() {
99  			throw new UnsupportedOperationException();
100 		}
101 	}
102 
103 	private static final Class[] DEST_CLASS = new Class[] { Class.class };
104 	private static final Class[] SOURCE_DISASSEMBLY = new Class[] { Disassembly.class };
105 
106 	private class DefaultClassConverter implements Converter {
107 		public Object convert(Class destinationClass, Object source, Locale locale)
108 				throws TransformationException {
109 			Disassembly disassembly = (Disassembly) source;
110 			Class[] destinationTypes = TransformerUtils.getDestinationClasses(
111 					getCopier(disassembly.getIndex()), ClassUtils.getClass(disassembly
112 							.getSource()));
113 			if (destinationTypes.length != 1) {
114 				throw new TransformationException(
115 						"Could not infer destination mapping for index "
116 								+ disassembly.getIndex());
117 			}
118 			return destinationTypes[0];
119 		}
120 
121 		public Class[] getDestinationClasses() {
122 			return DEST_CLASS;
123 		}
124 
125 		public Class[] getSourceClasses() {
126 			return SOURCE_DISASSEMBLY;
127 		}
128 	}
129 
130 	private class DisassemblyContainerCopier extends ContainerCopier {
131 		/**
132 		 * Create a new DisassemblyContainerCopier.
133 		 */
134 		public DisassemblyContainerCopier() {
135 			setPreferGrow(false);
136 		}
137 
138 		/**
139 		 * {@inheritDoc}
140 		 */
141 		protected Class determineDestinationContainedType(Object destination,
142 				Object sourceValue, Class containedValueClass, Locale locale) {
143 			try {
144 				return (Class) getClassConverter().convert(Class.class, sourceValue,
145 						locale);
146 			} catch (TransformationException e) {
147 				if (getComponents() == null) {
148 					//assume that destination was not empty; try to return type of existing element
149 					Class c = ClassUtils
150 							.getClass(((IndexedContainerReflector) getReflector(IndexedContainerReflector.class))
151 									.get(destination, ((Disassembly) sourceValue)
152 											.getIndex()));
153 					if (c != null) {
154 						return c;
155 					}
156 				}
157 				throw e;
158 			}
159 		}
160 
161 		/**
162 		 * {@inheritDoc}
163 		 */
164 		protected Object nestedTransform(Class destinationContainedType,
165 				Object destinationValue, Object sourceValue, Locale locale,
166 				Integer preferredTransformationType) {
167 			Disassembly d = (Disassembly) sourceValue;
168 			return TransformerUtils.transform(getCopier(d.getIndex()),
169 					destinationContainedType, destinationValue, d.getSource(), locale,
170 					preferredTransformationType);
171 		}
172 
173 	}
174 
175 	private Converter classConverter;
176 	private DisassemblyContainerCopier containerCopier = new DisassemblyContainerCopier();
177 
178 	/**
179 	 * Create a new DisassemblerCopier.
180 	 */
181 	public DisassemblerCopier() {
182 		super();
183 	}
184 
185 	/**
186 	 * Create a new DisassemblerCopier.
187 	 * @param components
188 	 */
189 	public DisassemblerCopier(Object[] components) {
190 		super(components);
191 	}
192 
193 	/**
194 	 * {@inheritDoc}
195 	 * @see net.sf.morph.transform.transformers.BaseTransformer#copyImpl(java.lang.Object, java.lang.Object, java.util.Locale, java.lang.Integer)
196 	 */
197 	protected void copyImpl(Object destination, Object source, Locale locale,
198 			Integer preferredTransformationType) throws Exception {
199 		int size;
200 		if (getComponents() == null) {
201 			SizableReflector szr = (SizableReflector) getReflector(SizableReflector.class);
202 			size = szr.getSize(destination);
203 		}
204 		else {
205 			size = getComponents().length;
206 		}
207 		containerCopier.copy(destination, new DisassemblyIterator(source, size), locale);
208 	}
209 
210 	/**
211 	 * {@inheritDoc}
212 	 * @see net.sf.morph.transform.transformers.BaseTransformer#getSourceClassesImpl()
213 	 */
214 	protected Class[] getSourceClassesImpl() throws Exception {
215 		Object[] components = getComponents();
216 		if (components == null) {
217 			return getNestedTransformer().getSourceClasses();
218 		}
219 		if (components.length == 0) {
220 			return new Class[0];
221 		}
222 		return TransformerUtils
223 				.getSourceClassIntersection((Transformer[]) getComponents());
224 	}
225 
226 	/**
227 	 * {@inheritDoc}
228 	 * @see net.sf.morph.transform.transformers.BaseTransformer#getDestinationClassesImpl()
229 	 */
230 	protected synchronized Class[] getDestinationClassesImpl() throws Exception {
231 		return containerCopier.getDestinationClasses();
232 	}
233 
234 	/**
235 	 * Get the Converter used to convert a Disassembly object to a destination class.
236 	 * @return the classConverter
237 	 */
238 	public synchronized Converter getClassConverter() {
239 		if (classConverter == null) {
240 			setClassConverter(new DefaultClassConverter());
241 		}
242 		return classConverter;
243 	}
244 
245 	/**
246 	 * Set the classConverter used to convert a Disassembly object to a destination class.
247 	 * @param classConverter the classConverter to set
248 	 */
249 	public synchronized void setClassConverter(Converter classConverter) {
250 		this.classConverter = classConverter;
251 	}
252 
253 }