001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.jaxws.utility;
020:
021: import org.apache.axis2.jaxws.ExceptionFactory;
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024:
025: import javax.activation.DataHandler;
026: import javax.imageio.IIOImage;
027: import javax.imageio.ImageIO;
028: import javax.imageio.ImageWriter;
029: import javax.imageio.stream.ImageOutputStream;
030: import javax.xml.transform.Result;
031: import javax.xml.transform.Source;
032: import javax.xml.transform.Transformer;
033: import javax.xml.transform.TransformerFactory;
034: import javax.xml.transform.stream.StreamResult;
035: import javax.xml.transform.stream.StreamSource;
036: import javax.xml.ws.WebServiceException;
037:
038: import java.awt.Image;
039: import java.awt.image.BufferedImage;
040: import java.io.ByteArrayOutputStream;
041: import java.io.IOException;
042: import java.io.InputStream;
043: import java.io.OutputStream;
044: import java.lang.reflect.Array;
045: import java.util.ArrayList;
046: import java.util.Calendar;
047: import java.util.Collection;
048: import java.util.Date;
049: import java.util.HashMap;
050: import java.util.HashSet;
051: import java.util.Hashtable;
052: import java.util.Iterator;
053: import java.util.List;
054: import java.util.Set;
055:
056: /**
057: * Provides utilities to convert an object into a different kind of Object. For example, convert a
058: * String[] into a List<String>
059: */
060: public class ConvertUtils {
061:
062: private static final Log log = LogFactory
063: .getLog(ConvertUtils.class);
064:
065: /**
066: * This method should return true if the convert method will succeed.
067: * <p/>
068: * Note that any changes to isConvertable() must also be accompanied by similar changes to
069: * convert()
070: *
071: * @param obj source object or class
072: * @param dest destination class
073: * @return boolean true if convert(..) can convert obj to the destination class
074: */
075: public static boolean isConvertable(Object obj, Class dest) {
076: Class src = null;
077:
078: if (obj != null) {
079: if (obj instanceof Class) {
080: src = (Class) obj;
081: } else {
082: src = obj.getClass();
083: }
084: }
085:
086: if (dest == null) {
087: return false;
088: }
089:
090: if (src == null) {
091: return true;
092: }
093:
094: // If we're directly assignable, we're good.
095: if (dest.isAssignableFrom(src)) {
096: return true;
097: }
098:
099: // If it's a wrapping conversion, we're good.
100: if (JavaUtils.getWrapperClass(src) == dest) {
101: return true;
102: }
103: if (JavaUtils.getWrapperClass(dest) == src) {
104: return true;
105: }
106:
107: // If it's List -> Array or vice versa, we're good.
108: if ((Collection.class.isAssignableFrom(src) || src.isArray())
109: && (Collection.class.isAssignableFrom(dest) || dest
110: .isArray())) {
111: return true;
112: }
113:
114: // Allow mapping of HashMaps to Hashtables
115: if (src == HashMap.class && dest == Hashtable.class)
116: return true;
117:
118: // Allow mapping of Calendar to Date
119: if (Calendar.class.isAssignableFrom(src) && dest == Date.class) {
120: return true;
121: }
122:
123: if (src.isPrimitive()) {
124: return isConvertable(JavaUtils.getWrapperClass(src), dest);
125: }
126:
127: if (InputStream.class.isAssignableFrom(src)
128: && dest == byte[].class) {
129: return true;
130: }
131:
132: if (Source.class.isAssignableFrom(src) && dest == byte[].class) {
133: return true;
134: }
135:
136: if (DataHandler.class.isAssignableFrom(src)
137: && isConvertable(byte[].class, dest)) {
138: return true;
139: }
140:
141: if (DataHandler.class.isAssignableFrom(src)
142: && dest == Image.class) {
143: return true;
144: }
145:
146: if (DataHandler.class.isAssignableFrom(src)
147: && dest == Source.class) {
148: return true;
149: }
150:
151: if (byte[].class.isAssignableFrom(src) && dest == String.class) {
152: return true;
153: }
154:
155: // If it's a MIME type mapping and we want a DataHandler,
156: // then we're good.
157: // REVIEW Do we want to support this
158: /*
159: if (dest.getName().equals("javax.activation.DataHandler")) {
160: String name = src.getName();
161: if (src == String.class
162: || src == java.awt.Image.class
163: || name.equals("javax.mail.internet.MimeMultipart")
164: || name.equals("javax.xml.transform.Source"))
165: return true;
166: }
167: */
168:
169: return false;
170: }
171:
172: /**
173: * Utility function to convert an Object to some desired Class.
174: * <p/>
175: * Normally this is used for T[] to List<T> processing. Other conversions are also done (i.e.
176: * HashMap <->Hashtable, etc.)
177: * <p/>
178: * Use the isConvertable() method to determine if conversion is possible. Note that any changes
179: * to convert() must also be accompanied by similar changes to isConvertable()
180: *
181: * @param arg the array to convert
182: * @param destClass the actual class we want
183: * @return object of destClass if conversion possible, otherwise returns arg
184: */
185: public static Object convert(Object arg, Class destClass)
186: throws WebServiceException {
187: if (destClass == null) {
188: return arg;
189: }
190:
191: if (arg != null && destClass.isAssignableFrom(arg.getClass())) {
192: return arg;
193: }
194:
195: if (log.isDebugEnabled()) {
196: String clsName = "null";
197: if (arg != null)
198: clsName = arg.getClass().getName();
199: log.debug("Converting an object of type " + clsName
200: + " to an object of type " + destClass.getName());
201: }
202:
203: // Convert between Calendar and Date
204: if (arg instanceof Calendar && destClass == Date.class) {
205: return ((Calendar) arg).getTime();
206: }
207:
208: // Convert between HashMap and Hashtable
209: if (arg instanceof HashMap && destClass == Hashtable.class) {
210: return new Hashtable((HashMap) arg);
211: }
212:
213: if (arg instanceof InputStream && destClass == byte[].class) {
214:
215: try {
216: InputStream is = (InputStream) arg;
217: return getBytesFromStream(is);
218: } catch (IOException e) {
219: throw ExceptionFactory.makeWebServiceException(e);
220: }
221: }
222:
223: if (arg instanceof Source && destClass == byte[].class) {
224: try {
225: if (arg instanceof StreamSource) {
226: InputStream is = ((StreamSource) arg)
227: .getInputStream();
228: if (is != null) {
229: return getBytesFromStream(is);
230: }
231: }
232: ByteArrayOutputStream out = new ByteArrayOutputStream();
233: Result result = new StreamResult(out);
234: Transformer transformer = TransformerFactory
235: .newInstance().newTransformer();
236: transformer.transform((Source) arg, result);
237: byte[] bytes = out.toByteArray();
238: return bytes;
239:
240: } catch (Exception e) {
241: throw ExceptionFactory.makeWebServiceException(e);
242: }
243: }
244:
245: if (arg instanceof DataHandler) {
246: try {
247: InputStream is = ((DataHandler) arg).getInputStream();
248: if (destClass == Image.class) {
249: return ImageIO.read(is);
250: } else if (destClass == Source.class) {
251: return new StreamSource(is);
252: }
253: byte[] bytes = getBytesFromStream(is);
254: return convert(bytes, destClass);
255: } catch (Exception e) {
256: throw ExceptionFactory.makeWebServiceException(e);
257: }
258: }
259:
260: if (arg instanceof byte[] && destClass == String.class) {
261: return new String((byte[]) arg);
262: }
263:
264: // If the destination is an array and the source
265: // is a suitable component, return an array with
266: // the single item.
267: /* REVIEW do we need to support atomic to array conversion ?
268: if (arg != null &&
269: destClass.isArray() &&
270: !destClass.getComponentType().equals(Object.class) &&
271: destClass.getComponentType().isAssignableFrom(arg.getClass())) {
272: Object array =
273: Array.newInstance(destClass.getComponentType(), 1);
274: Array.set(array, 0, arg);
275: return array;
276: }
277: */
278:
279: // Return if no conversion is available
280: if (!(arg instanceof Collection || (arg != null && arg
281: .getClass().isArray()))) {
282: return arg;
283: }
284:
285: if (arg == null) {
286: return arg;
287: }
288:
289: // The arg may be an array or List
290: Object destValue = null;
291: int length = 0;
292: if (arg.getClass().isArray()) {
293: length = Array.getLength(arg);
294: } else {
295: length = ((Collection) arg).size();
296: }
297: if (destClass.isArray()) {
298: if (destClass.getComponentType().isPrimitive()) {
299:
300: Object array = Array.newInstance(destClass
301: .getComponentType(), length);
302: // Assign array elements
303: if (arg.getClass().isArray()) {
304: for (int i = 0; i < length; i++) {
305: Array.set(array, i, Array.get(arg, i));
306: }
307: } else {
308: int idx = 0;
309: for (Iterator i = ((Collection) arg).iterator(); i
310: .hasNext();) {
311: Array.set(array, idx++, i.next());
312: }
313: }
314: destValue = array;
315:
316: } else {
317: Object[] array;
318: try {
319: array = (Object[]) Array.newInstance(destClass
320: .getComponentType(), length);
321: } catch (Exception e) {
322: return arg;
323: }
324:
325: // Use convert to assign array elements.
326: if (arg.getClass().isArray()) {
327: for (int i = 0; i < length; i++) {
328: array[i] = convert(Array.get(arg, i), destClass
329: .getComponentType());
330: }
331: } else {
332: int idx = 0;
333: for (Iterator i = ((Collection) arg).iterator(); i
334: .hasNext();) {
335: array[idx++] = convert(i.next(), destClass
336: .getComponentType());
337: }
338: }
339: destValue = array;
340: }
341: } else if (Collection.class.isAssignableFrom(destClass)) {
342: Collection newList = null;
343: try {
344: // if we are trying to create an interface, build something
345: // that implements the interface
346: if (destClass == Collection.class
347: || destClass == List.class) {
348: newList = new ArrayList();
349: } else if (destClass == Set.class) {
350: newList = new HashSet();
351: } else {
352: newList = (Collection) destClass.newInstance();
353: }
354: } catch (Exception e) {
355: // No FFDC code needed
356: // Couldn't build one for some reason... so forget it.
357: return arg;
358: }
359:
360: if (arg.getClass().isArray()) {
361: for (int j = 0; j < length; j++) {
362: newList.add(Array.get(arg, j));
363: }
364: } else {
365: for (Iterator j = ((Collection) arg).iterator(); j
366: .hasNext();) {
367: newList.add(j.next());
368: }
369: }
370: destValue = newList;
371: } else {
372: destValue = arg;
373: }
374: return destValue;
375: }
376:
377: private static byte[] getBytesFromStream(InputStream is)
378: throws IOException {
379: // TODO This code assumes that available is the length of the stream.
380: byte[] bytes = new byte[is.available()];
381: is.read(bytes);
382: return bytes;
383: }
384: }
|