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.camel.converter.jaxb;
018    
019    import java.io.InputStream;
020    import java.io.Reader;
021    import java.io.StringReader;
022    import java.io.StringWriter;
023    
024    import javax.xml.bind.JAXBContext;
025    import javax.xml.bind.JAXBException;
026    import javax.xml.bind.Unmarshaller;
027    import javax.xml.bind.Marshaller;
028    import javax.xml.bind.annotation.XmlRootElement;
029    import javax.xml.bind.util.JAXBSource;
030    import javax.xml.transform.Source;
031    
032    import org.apache.camel.RuntimeCamelException;
033    import org.apache.camel.TypeConverter;
034    import org.apache.camel.spi.TypeConverterAware;
035    import org.apache.commons.logging.Log;
036    import org.apache.commons.logging.LogFactory;
037    
038    /**
039     * @version $Revision: 1.1 $
040     */
041    public class FallbackTypeConverter implements TypeConverter, TypeConverterAware {
042        private static final transient Log LOG = LogFactory.getLog(FallbackTypeConverter.class);
043        private TypeConverter parentTypeConverter;
044        private boolean prettyPrint = true;
045    
046        public boolean isPrettyPrint() {
047            return prettyPrint;
048        }
049    
050        public void setPrettyPrint(boolean prettyPrint) {
051            this.prettyPrint = prettyPrint;
052        }
053    
054        public void setTypeConverter(TypeConverter parentTypeConverter) {
055            this.parentTypeConverter = parentTypeConverter;
056        }
057    
058        public <T> T convertTo(Class<T> type, Object value) {
059            try {
060                if (isJaxbType(type)) {
061                    return unmarshall(type, value);
062                }
063                if (value != null) {
064                    if (isJaxbType(value.getClass())) {
065                        return marshall(type, value);
066                    }
067                }
068                return null;
069            } catch (JAXBException e) {
070                throw new RuntimeCamelException(e);
071            }
072        }
073    
074        protected <T> boolean isJaxbType(Class<T> type) {
075            XmlRootElement element = type.getAnnotation(XmlRootElement.class);
076            boolean jaxbType = element != null;
077            return jaxbType;
078        }
079    
080        /**
081         * Lets try parse via JAXB
082         */
083        protected <T> T unmarshall(Class<T> type, Object value) throws JAXBException {
084            JAXBContext context = createContext(type);
085            Unmarshaller unmarshaller = context.createUnmarshaller();
086    
087            if (parentTypeConverter != null) {
088                InputStream inputStream = parentTypeConverter.convertTo(InputStream.class, value);
089                if (inputStream != null) {
090                    Object unmarshalled = unmarshaller.unmarshal(inputStream);
091                    return type.cast(unmarshalled);
092                }
093                Reader reader = parentTypeConverter.convertTo(Reader.class, value);
094                if (reader != null) {
095                    Object unmarshalled = unmarshaller.unmarshal(reader);
096                    return type.cast(unmarshalled);
097                }
098                Source source = parentTypeConverter.convertTo(Source.class, value);
099                if (source != null) {
100                    Object unmarshalled = unmarshaller.unmarshal(source);
101                    return type.cast(unmarshalled);
102                }
103            }
104            if (value instanceof String) {
105                value = new StringReader((String)value);
106            }
107            if (value instanceof InputStream) {
108                Object unmarshalled = unmarshaller.unmarshal((InputStream)value);
109                return type.cast(unmarshalled);
110            }
111            if (value instanceof Reader) {
112                Object unmarshalled = unmarshaller.unmarshal((Reader)value);
113                return type.cast(unmarshalled);
114            }
115            return null;
116        }
117    
118        protected <T> T marshall(Class<T> type, Object value) throws JAXBException {
119            if (parentTypeConverter != null) {
120                // lets convert the object to a JAXB source and try convert that to
121                // the required source
122                JAXBContext context = createContext(value.getClass());
123                JAXBSource source = new JAXBSource(context, value);
124                T answer = parentTypeConverter.convertTo(type, source);
125                if (answer == null) {
126                    // lets try a stream
127                    StringWriter buffer = new StringWriter();
128                    Marshaller marshaller = context.createMarshaller();
129                    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, isPrettyPrint() ? Boolean.TRUE : Boolean.FALSE);
130                    marshaller.marshal(value, buffer);
131                    return parentTypeConverter.convertTo(type, buffer.toString());
132                }
133                return answer;
134            }
135    
136            // lets try convert to the type from JAXB
137            return null;
138        }
139    
140        protected <T> JAXBContext createContext(Class<T> type) throws JAXBException {
141            JAXBContext context = JAXBContext.newInstance(type);
142            return context;
143        }
144    }