001: /*--
002:
003: Copyright (C) 2002-2005 Adrian Price.
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: 1. Redistributions of source code must retain the above copyright
011: notice, this list of conditions, and the following disclaimer.
012:
013: 2. Redistributions in binary form must reproduce the above copyright
014: notice, this list of conditions, and the disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The names "OBE" and "Open Business Engine" must not be used to
019: endorse or promote products derived from this software without prior
020: written permission. For written permission, please contact
021: adrianprice@sourceforge.net.
022:
023: 4. Products derived from this software may not be called "OBE" or
024: "Open Business Engine", nor may "OBE" or "Open Business Engine"
025: appear in their name, without prior written permission from
026: Adrian Price (adrianprice@users.sourceforge.net).
027:
028: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
029: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
030: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
031: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
032: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
033: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
034: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
035: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
036: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
037: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
038: POSSIBILITY OF SUCH DAMAGE.
039:
040: For more information on OBE, please see
041: <http://obe.sourceforge.net/>.
042:
043: */
044:
045: package org.obe.engine.util;
046:
047: import org.apache.commons.logging.Log;
048: import org.apache.commons.logging.LogFactory;
049: import org.obe.OBERuntimeException;
050: import org.obe.client.api.repository.RepositoryException;
051: import org.obe.spi.service.DataConverter;
052: import org.obe.spi.service.ServiceManager;
053: import org.obe.util.DateUtilities;
054: import org.obe.xpdl.model.data.DataTypes;
055: import org.w3c.dom.Document;
056: import org.w3c.dom.Element;
057: import org.w3c.dom.Node;
058: import org.w3c.dom.NodeList;
059: import org.xml.sax.InputSource;
060: import org.xml.sax.SAXException;
061: import org.xml.sax.XMLReader;
062: import org.xml.sax.helpers.XMLReaderFactory;
063:
064: import javax.ejb.EJBHome;
065: import javax.ejb.EJBObject;
066: import javax.ejb.Handle;
067: import javax.ejb.HomeHandle;
068: import javax.xml.parsers.DocumentBuilder;
069: import javax.xml.parsers.DocumentBuilderFactory;
070: import javax.xml.parsers.ParserConfigurationException;
071: import javax.xml.transform.*;
072: import javax.xml.transform.dom.DOMResult;
073: import javax.xml.transform.dom.DOMSource;
074: import javax.xml.transform.sax.SAXSource;
075: import javax.xml.transform.stream.StreamResult;
076: import javax.xml.transform.stream.StreamSource;
077: import java.io.*;
078: import java.net.URL;
079: import java.rmi.RemoteException;
080: import java.security.Principal;
081: import java.text.ParseException;
082: import java.util.*;
083:
084: /**
085: * Converts data between different types.
086: *
087: * @author Adrian Price
088: */
089: public final class BasicDataConverter implements DataConverter {
090: private static final Log _logger = LogFactory
091: .getLog(BasicDataConverter.class);
092: private static final Object EMPTY_ARRAY = new Object[0];
093: private static final int MAX_VALUE_LENGTH = 35;
094: private static final ThreadLocal _documentBuilderFactory = new ThreadLocal();
095: private static final ThreadLocal _transformerFactory = new ThreadLocal();
096: private final ServiceManager _svcMgr;
097: private final Map _templatesMap = Collections
098: .synchronizedMap(new HashMap());
099:
100: private static void throwDataConversionException(Object src,
101: Class clazz) {
102: throw new OBERuntimeException("Cannot convert " + truncate(src)
103: + " to " + clazz);
104: }
105:
106: private static String truncate(Object obj) {
107: String s = null;
108: if (obj != null) {
109: s = obj.toString();
110: if (s.length() > MAX_VALUE_LENGTH)
111: s = s.substring(0, MAX_VALUE_LENGTH - 3) + "...";
112: }
113: return s;
114: }
115:
116: private static DocumentBuilder getDocumentBuilder()
117: throws RepositoryException {
118:
119: try {
120: return getDocumentBuilderFactory().newDocumentBuilder();
121: } catch (ParserConfigurationException e) {
122: throw new RepositoryException(e);
123: }
124: }
125:
126: // DocumentBuilder factories are not threadsafe, so we must keep one per thread.
127: private static DocumentBuilderFactory getDocumentBuilderFactory() {
128: DocumentBuilderFactory factory = (DocumentBuilderFactory) _documentBuilderFactory
129: .get();
130: if (factory == null) {
131: factory = DocumentBuilderFactory.newInstance();
132: factory.setCoalescing(false);
133: factory.setExpandEntityReferences(true);
134: factory.setIgnoringComments(true);
135: factory.setIgnoringElementContentWhitespace(false);
136: factory.setNamespaceAware(true);
137: factory.setValidating(false);
138: _documentBuilderFactory.set(factory);
139:
140: if (_logger.isDebugEnabled())
141: _logger.debug("Created new " + factory);
142: }
143: return factory;
144: }
145:
146: // Transformer factories are not threadsafe, so we must keep one per thread.
147: private static TransformerFactory getTransformerFactory() {
148: TransformerFactory factory = (TransformerFactory) _transformerFactory
149: .get();
150: if (factory == null) {
151: factory = TransformerFactory.newInstance();
152: _transformerFactory.set(factory);
153:
154: if (_logger.isDebugEnabled())
155: _logger.debug("Created new " + factory);
156: }
157: return factory;
158: }
159:
160: private static String toIntegerString(String s) {
161: int dotpos = s.indexOf('.');
162: if (dotpos != -1)
163: s = s.substring(0, dotpos);
164: return s;
165: }
166:
167: public BasicDataConverter(ServiceManager svcMgr) {
168: _svcMgr = svcMgr;
169: }
170:
171: public ServiceManager getServiceManager() {
172: return _svcMgr;
173: }
174:
175: public String getServiceName() {
176: return SERVICE_NAME;
177: }
178:
179: public void init() {
180: }
181:
182: public void exit() {
183: }
184:
185: public Object convertValue(Object src, int xpdlType) {
186: return convertValue(src, DataTypes.classForType(xpdlType));
187: }
188:
189: public Object convertValue(Object src, Class type) {
190: Object dest = null;
191: if (src == null || type.isInstance(src)) {
192: dest = src;
193: } else if (type.isArray()) {
194: dest = toArray(src, type);
195: } else if (type == Boolean.class || type == Boolean.TYPE) {
196: dest = toBoolean(src) ? Boolean.TRUE : Boolean.FALSE;
197: } else if (type == Byte.class || type == Byte.TYPE) {
198: dest = new Byte(toByte(src));
199: } else if (type == Character.class || type == Character.TYPE) {
200: dest = new Character(toChar(src));
201: } else if (type == Double.class || type == Double.TYPE) {
202: dest = new Double(toDouble(src));
203: } else if (type == Float.class || type == Float.TYPE) {
204: dest = new Float(toFloat(src));
205: } else if (type == Integer.class || type == Integer.TYPE) {
206: dest = new Integer(toInt(src));
207: } else if (type == Long.class || type == Long.TYPE) {
208: dest = new Long(toLong(src));
209: } else if (type == Short.class || type == Short.TYPE) {
210: dest = new Short(toShort(src));
211: } else if (type == String.class) {
212: dest = toString(src);
213: } else {
214: try {
215: if (EJBHome.class.isAssignableFrom(type)) {
216: dest = toEJBHome(src);
217: } else if (EJBObject.class.isAssignableFrom(type)) {
218: dest = toEJBObject(src);
219: } else if (Handle.class.isAssignableFrom(type)) {
220: dest = toHandle(src);
221: } else if (HomeHandle.class.isAssignableFrom(type)) {
222: dest = toHomeHandle(src);
223: } else if (Source.class.isAssignableFrom(type)) {
224: dest = toSource(src);
225: } else if (InputSource.class.isAssignableFrom(type)) {
226: dest = toInputSource(src);
227: } else if (Date.class.isAssignableFrom(type)) {
228: dest = toDate(src);
229: } else if (Document.class.isAssignableFrom(type)) {
230: dest = toDocument(src);
231: } else if (Node.class.isAssignableFrom(type)) {
232: dest = toDocument(src);
233: } else if (Element.class.isAssignableFrom(type)) {
234: dest = toElement(src);
235: } else if (Properties.class.isAssignableFrom(type)) {
236: dest = toProperties(src);
237: } else {
238: throwDataConversionException(src, type);
239: }
240: } catch (IOException e) {
241: throw new OBERuntimeException(e);
242: } catch (SAXException e) {
243: throw new OBERuntimeException(e);
244: }
245: if (dest != null && !type.isAssignableFrom(dest.getClass())) {
246: throwDataConversionException(src, type);
247: }
248: }
249: return dest;
250: }
251:
252: public Object convertValueEx(Object src, Class type) {
253: Object dest;
254: if (type != Object.class) {
255: dest = convertValue(src, type);
256: } else if (src instanceof byte[]) {
257: dest = toDocument(src);
258: } else if (src instanceof Handle) {
259: try {
260: dest = toEJBObject(src);
261: } catch (RemoteException e) {
262: throw new OBERuntimeException(e);
263: }
264: } else {
265: dest = src;
266: }
267: return dest;
268: }
269:
270: public Object toArray(Object src) {
271: return toArray(src, null);
272: }
273:
274: public Object toArray(Object src, Class type) {
275: if (type != null && !type.isArray())
276: throw new IllegalArgumentException(String.valueOf(type));
277:
278: Object dest;
279: if (src == null) {
280: dest = EMPTY_ARRAY;
281: } else if (src.getClass().isArray()) {
282: dest = src;
283: } else if (src instanceof Collection) {
284: dest = ((Collection) src).toArray();
285: } else if (src instanceof Enumeration) {
286: List list = new ArrayList();
287: for (Enumeration e = (Enumeration) src; e.hasMoreElements();)
288: list.add(e.nextElement());
289: dest = list.toArray();
290: } else if (src instanceof Iterator) {
291: List list = new ArrayList();
292: for (Iterator iter = (Iterator) src; iter.hasNext();)
293: list.add(iter.next());
294: dest = list.toArray();
295: } else if (src instanceof Map) {
296: dest = ((Map) src).values().toArray();
297: } else {
298: dest = new Object[] { src };
299: }
300:
301: // We have an array, but it might not be compatible with the array
302: // type the caller requested. For now, we won't attempt to convert.
303: // TODO: implement array-type conversions.
304: if (type != null && src != null
305: && !type.isAssignableFrom(src.getClass())) {
306:
307: throwDataConversionException(src, type);
308: }
309:
310: return dest;
311: }
312:
313: public boolean toBoolean(Object src) {
314: boolean dest = false;
315: if (src instanceof Boolean) {
316: dest = ((Boolean) src).booleanValue();
317: } else if (src instanceof String) {
318: dest = Boolean.valueOf((String) src).booleanValue();
319: } else {
320: throwDataConversionException(src, Boolean.TYPE);
321: }
322: return dest;
323: }
324:
325: public byte toByte(Object src) {
326: byte dest = (byte) 0;
327: if (src instanceof Number) {
328: dest = ((Number) src).byteValue();
329: } else if (src instanceof String) {
330: dest = Byte.parseByte((String) src);
331: } else {
332: throwDataConversionException(src, Byte.TYPE);
333: }
334: return dest;
335: }
336:
337: public char toChar(Object src) {
338: char dest = '\0';
339: if (src instanceof Number) {
340: dest = (char) ((Number) src).shortValue();
341: } else {
342: throwDataConversionException(src, Character.TYPE);
343: }
344: return dest;
345: }
346:
347: public Date toDate(Object src) {
348: Date dest = null;
349: if (src == null) {
350: dest = null;
351: } else if (src instanceof Date) {
352: dest = (Date) src;
353: } else if (src instanceof String) {
354: try {
355: dest = DateUtilities.getInstance().parse((String) src);
356: } catch (ParseException e) {
357: throw new OBERuntimeException(e);
358: }
359: }
360: return dest;
361: }
362:
363: public Document toDocument(Object src) {
364: Document dest;
365: if (src == null) {
366: dest = null;
367: } else if (src instanceof Document) {
368: dest = (Document) src;
369: } else if (src instanceof Node) {
370: dest = ((Node) src).getOwnerDocument();
371: } else if (src instanceof NodeList) {
372: dest = ((NodeList) src).item(0).getOwnerDocument();
373: } else {
374: try {
375: InputSource in = toInputSource(src);
376: DocumentBuilder docBuilder = getDocumentBuilder();
377: docBuilder.setEntityResolver(_svcMgr
378: .getResourceRepository());
379: dest = docBuilder.parse(in);
380: } catch (Exception e) {
381: throw new OBERuntimeException(e);
382: }
383: }
384: return dest;
385: }
386:
387: public double toDouble(Object src) {
388: double dest = 0.0;
389: if (src instanceof Number) {
390: dest = ((Number) src).doubleValue();
391: } else if (src instanceof String) {
392: dest = Double.parseDouble((String) src);
393: } else {
394: throwDataConversionException(src, Double.TYPE);
395: }
396: return dest;
397: }
398:
399: public EJBHome toEJBHome(Object src) throws RemoteException {
400: EJBHome dest = null;
401: if (src == null) {
402: dest = null;
403: } else if (src instanceof EJBHome) {
404: dest = (EJBHome) src;
405: } else if (src instanceof HomeHandle) {
406: dest = ((HomeHandle) src).getEJBHome();
407: } else if (src instanceof EJBObject) {
408: dest = ((EJBObject) src).getEJBHome();
409: } else {
410: throwDataConversionException(src, EJBHome.class);
411: }
412: return dest;
413: }
414:
415: public EJBObject toEJBObject(Object src) throws RemoteException {
416: EJBObject dest = null;
417: if (src == null) {
418: dest = null;
419: } else if (src instanceof EJBObject) {
420: dest = (EJBObject) src;
421: } else if (src instanceof Handle) {
422: dest = ((Handle) src).getEJBObject();
423: } else {
424: throwDataConversionException(src, EJBObject.class);
425: }
426: return dest;
427: }
428:
429: public Element toElement(Object src) {
430: Element dest;
431: if (src == null) {
432: dest = null;
433: } else if (src instanceof Element) {
434: dest = (Element) src;
435: } else if (src instanceof Document) {
436: dest = ((Document) src).getDocumentElement();
437: } else if (src instanceof NodeList) {
438: dest = (Element) ((NodeList) src).item(0);
439: } else {
440: dest = toDocument(src).getDocumentElement();
441: }
442: return dest;
443: }
444:
445: public float toFloat(Object src) {
446: float dest = 0.0F;
447: if (src instanceof Number) {
448: dest = ((Number) src).floatValue();
449: } else if (src instanceof String) {
450: dest = Float.parseFloat((String) src);
451: } else {
452: throwDataConversionException(src, Float.TYPE);
453: }
454: return dest;
455: }
456:
457: public Handle toHandle(Object src) throws RemoteException {
458: Handle dest = null;
459: if (src == null) {
460: dest = null;
461: } else if (src instanceof Handle) {
462: dest = (Handle) src;
463: } else if (src instanceof EJBObject) {
464: dest = ((EJBObject) src).getHandle();
465: } else {
466: throwDataConversionException(src, Handle.class);
467: }
468: return dest;
469: }
470:
471: public HomeHandle toHomeHandle(Object src) throws RemoteException {
472: HomeHandle dest = null;
473: if (src == null) {
474: dest = null;
475: } else if (src instanceof HomeHandle) {
476: dest = (HomeHandle) src;
477: } else if (src instanceof EJBHome) {
478: dest = ((EJBHome) src).getHomeHandle();
479: } else {
480: throwDataConversionException(src, HomeHandle.class);
481: }
482: return dest;
483: }
484:
485: public InputStream toInputStream(Object src) throws IOException {
486: InputStream dest = null;
487: if (src == null) {
488: dest = null;
489: } else if (src instanceof InputStream) {
490: dest = (InputStream) src;
491: } else if (src instanceof URL) {
492: dest = ((URL) src).openStream();
493: } else if (src instanceof File) {
494: dest = new FileInputStream((File) src);
495: } else if (src instanceof byte[]) {
496: dest = new ByteArrayInputStream((byte[]) src);
497: } else if (src instanceof String || src instanceof StringBuffer) {
498: if (src instanceof StringBuffer)
499: src = src.toString();
500:
501: // N.B. This is a 'best guess' at interpreting whether src is the
502: // name of a file to read, or a string source to be read.
503: File file = new File((String) src);
504: if (file.exists())
505: dest = new FileInputStream(file);
506: else
507: dest = new ByteArrayInputStream(((String) src)
508: .getBytes());
509: } else {
510: throwDataConversionException(src, InputStream.class);
511: }
512: return dest;
513: }
514:
515: public InputSource toInputSource(Object src) throws IOException {
516: InputSource dest;
517: if (src == null) {
518: dest = null;
519: } else if (src instanceof InputSource) {
520: dest = (InputSource) src;
521: } else {
522: dest = new InputSource(toInputStream(src));
523: }
524: return dest;
525: }
526:
527: public int toInt(Object src) {
528: int dest = 0;
529: if (src instanceof Number) {
530: dest = ((Number) src).intValue();
531: } else if (src instanceof String) {
532: dest = Integer.parseInt(toIntegerString((String) src));
533: } else {
534: throwDataConversionException(src, Integer.TYPE);
535: }
536: return dest;
537: }
538:
539: public long toLong(Object src) {
540: long dest = 0L;
541: if (src instanceof Number) {
542: dest = ((Number) src).longValue();
543: } else if (src instanceof String) {
544: dest = Long.parseLong(toIntegerString((String) src));
545: } else {
546: throwDataConversionException(src, Long.TYPE);
547: }
548: return dest;
549: }
550:
551: public Properties toProperties(Object src) {
552: // Assume it's in Java .properties file format.
553: Properties dest = null;
554: try {
555: if (src == null) {
556: dest = null;
557: } else if (src instanceof Properties) {
558: dest = (Properties) src;
559: } else if (src instanceof Map) {
560: dest = new Properties();
561: Set entries = ((Map) src).entrySet();
562: for (Iterator iter = entries.iterator(); iter.hasNext();) {
563: Map.Entry entry = (Map.Entry) iter.next();
564: Object value = entry.getValue();
565: if (value != null) {
566: dest.setProperty(entry.getKey().toString(),
567: value.toString());
568: }
569: }
570: } else if (src instanceof String) {
571: String text = (String) src;
572: InputStream in = new ByteArrayInputStream(text
573: .getBytes("UTF-8"));
574: dest = new Properties();
575: dest.load(in);
576: } else {
577: throwDataConversionException(src, Properties.class);
578: }
579: } catch (Exception e) {
580: throwDataConversionException(src, Properties.class);
581: }
582: return dest;
583: }
584:
585: public short toShort(Object src) {
586: short dest = (short) 0;
587: if (src instanceof Number) {
588: dest = ((Number) src).shortValue();
589: } else if (src instanceof String) {
590: dest = Short.parseShort((String) src);
591: } else {
592: throwDataConversionException(src, Short.TYPE);
593: }
594: return dest;
595: }
596:
597: public Source toSource(Object src) throws IOException, SAXException {
598:
599: Object dest = null;
600: InputSource in = null;
601: if (src == null) {
602: dest = null;
603: } else if (src instanceof Node) {
604: dest = new DOMSource((Node) src);
605: } else if (src instanceof InputStream) {
606: in = new InputSource((InputStream) src);
607: } else if (src instanceof URL) {
608: in = new InputSource(((URL) src).openStream());
609: } else if (src instanceof File) {
610: in = new InputSource(new FileInputStream((File) src));
611: } else if (src instanceof byte[]) {
612: in = new InputSource(new ByteArrayInputStream((byte[]) src));
613: } else if (src instanceof String) {
614: in = new InputSource(new StringReader((String) src));
615: } else {
616: throwDataConversionException(src, Source.class);
617: }
618: if (dest == null)
619: dest = new SAXSource(in);
620: if (dest instanceof SAXSource) {
621: XMLReader xmlreader = XMLReaderFactory.createXMLReader();
622: xmlreader
623: .setEntityResolver(_svcMgr.getResourceRepository());
624: ((SAXSource) dest).setXMLReader(xmlreader);
625: }
626: return (Source) dest;
627: }
628:
629: public String toString(Object src) {
630: String s;
631: try {
632: if (src == null) {
633: s = null;
634: } else if (src instanceof String) {
635: s = (String) src;
636: } else if (src instanceof byte[]) {
637: s = new String((byte[]) src, "UTF-8");
638: } else if (src instanceof Principal) {
639: s = ((Principal) src).getName();
640: // } else if (src instanceof NodeList) {
641: // TODO: figure out how to stringify NodeLists.
642: } else if (src instanceof Node) {
643: StringWriter out = new StringWriter();
644: getTransformer(null).transform(toSource(src),
645: new StreamResult(out));
646: s = out.toString();
647: } else if (src instanceof Date) {
648: s = DateUtilities.getInstance().format((Date) src);
649: } else {
650: s = src.toString();
651: }
652: } catch (Exception e) {
653: throw new OBERuntimeException(e);
654: }
655: return s;
656: }
657:
658: public String toString(Object value, int len) {
659: String s = toString(value);
660: if (s != null && 0 < len && len < s.length())
661: s = s.substring(0, len - 1);
662: return s;
663: }
664:
665: public Document transform(Object input, String transformURI,
666: Map parms) throws RepositoryException {
667:
668: try {
669: Source source = toSource(input);
670: DOMResult result = new DOMResult();
671: Transformer transformer = getTransformer(transformURI);
672: if (parms != null) {
673: for (Iterator iter = parms.entrySet().iterator(); iter
674: .hasNext();) {
675:
676: Map.Entry entry = (Map.Entry) iter.next();
677: transformer.setParameter((String) entry.getKey(),
678: entry.getValue());
679: }
680: }
681: transformer.transform(source, result);
682: return toDocument(result.getNode());
683: } catch (TransformerException e) {
684: throw new RepositoryException(e);
685: } catch (IOException e) {
686: throw new RepositoryException(e);
687: } catch (SAXException e) {
688: throw new RepositoryException(e);
689: }
690: }
691:
692: public Transformer getTransformer(String transformURI)
693: throws RepositoryException {
694:
695: InputStream in = null;
696: try {
697: if (transformURI != null) {
698: Templates templates = (Templates) _templatesMap
699: .get(transformURI);
700: if (templates == null) {
701: in = _svcMgr.getResourceRepository().findEntity(
702: transformURI);
703: templates = getTransformerFactory().newTemplates(
704: new StreamSource(in));
705: _templatesMap.put(transformURI, templates);
706:
707: if (_logger.isDebugEnabled())
708: _logger.debug("Created new " + templates);
709: }
710: return templates.newTransformer();
711: } else {
712: return getTransformerFactory().newTransformer();
713: }
714: } catch (TransformerConfigurationException e) {
715: throw new RepositoryException(e);
716: } finally {
717: if (in != null) {
718: try {
719: in.close();
720: } catch (IOException e) {
721: _logger
722: .error(
723: "Error closing transformer input stream",
724: e);
725: }
726: }
727: }
728: }
729: }
|