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.impl;
018    
019    import org.apache.camel.CamelContext;
020    import org.apache.camel.Exchange;
021    import org.apache.camel.Message;
022    import org.apache.camel.NoTypeConversionAvailableException;
023    import org.apache.camel.TypeConverter;
024    import org.apache.camel.impl.converter.DefaultTypeConverter;
025    import org.apache.camel.util.UuidGenerator;
026    
027    /**
028     * A base class for implementation inheritence providing the core
029     * {@link Message} body handling features but letting the derived class deal
030     * with headers.
031     *
032     * Unless a specific provider wishes to do something particularly clever with
033     * headers you probably want to just derive from {@link DefaultMessage}
034     *
035     * @version $Revision: 13620 $
036     */
037    public abstract class MessageSupport implements Message {
038        private static final UuidGenerator DEFALT_ID_GENERATOR = new UuidGenerator();
039        private Exchange exchange;
040        private Object body;
041        private String messageId;
042    
043        public Object getBody() {
044            if (body == null) {
045                body = createBody();
046            }
047            return body;
048        }
049    
050        @SuppressWarnings({"unchecked" })
051        public <T> T getBody(Class<T> type) {
052            return getBody(type, getBody());
053        }
054    
055        protected <T> T getBody(Class<T> type, Object body) {
056            // same instance type
057            if (type.isInstance(body)) {
058                return type.cast(body);
059            }
060    
061            Exchange e = getExchange();
062            if (e != null) {
063                CamelContext camelContext = e.getContext();
064                if (camelContext != null) {
065                    boolean tryConvert = true;
066                    TypeConverter converter = camelContext.getTypeConverter();
067                    // if its the default type converter then use a performance shortcut to check if it can convert it
068                    // this is faster than getting throwing and catching NoTypeConversionAvailableException
069                    // the StreamCachingInterceptor will attempt to convert the payload to a StremCache for caching purpose
070                    // so we get invoked on each node the exchange passes. So this is a little performance optimization
071                    // to avoid the excessive exception handling
072                    if (body != null) {
073                        // we can only check if there is no converter meaning we have tried to convert it beforehand
074                        // and then knows for sure there is no converter possible
075                        tryConvert = !hasNoConverterFor(converter, type, body.getClass());
076                    }
077                    if (tryConvert) {
078                        try {
079                            // lets first try converting the body itself first
080                            // as for some types like InputStream v Reader its more efficient to do the transformation
081                            // from the body itself as its got efficient implementations of them, before trying the
082                            // message
083                            return converter.convertTo(type, e, body);
084                        } catch (NoTypeConversionAvailableException ex) {
085                            // ignore
086                        }
087                    }
088    
089                    // fallback to the message itself (e.g. used in camel-http)
090                    tryConvert = !hasNoConverterFor(converter, type, this.getClass());
091                    if (tryConvert) {
092                        try {
093                            return converter.convertTo(type, e, this);
094                        } catch (NoTypeConversionAvailableException ex) {
095                            // ignore
096                        }
097                    }
098                }
099            }
100    
101            // not possible to convert
102            throw new NoTypeConversionAvailableException(body, type);
103        }
104    
105        private boolean hasNoConverterFor(TypeConverter converter, Class toType, Class fromType) {
106            if (converter instanceof DefaultTypeConverter) {
107                DefaultTypeConverter defaultTypeConverter = (DefaultTypeConverter) converter;
108                // we can only check if there is no converter meaning we have tried to convert it beforehand
109                // and then knows for sure there is no converter possible
110                return defaultTypeConverter.hasNoConverterFor(toType, fromType);
111            }
112            return false;
113        }
114    
115        public void setBody(Object body) {
116            this.body = body;
117        }
118    
119        public <T> void setBody(Object value, Class<T> type) {
120            Exchange e = getExchange();
121            if (e != null) {
122                T v = e.getContext().getTypeConverter().convertTo(type, e, value);
123                if (v != null) {
124                    value = v;
125                }
126            }
127            setBody(value);
128        }
129    
130        public Message copy() {
131            Message answer = newInstance();
132            answer.copyFrom(this);
133            return answer;
134        }
135    
136        public void copyFrom(Message that) {
137            setMessageId(that.getMessageId());
138            setBody(that.getBody());
139            getHeaders().putAll(that.getHeaders());
140            getAttachments().putAll(that.getAttachments());
141        }
142    
143        public Exchange getExchange() {
144            return exchange;
145        }
146    
147        public void setExchange(Exchange exchange) {
148            this.exchange = exchange;
149        }
150    
151        /**
152         * Returns a new instance
153         */
154        public abstract Message newInstance();
155    
156        /**
157         * A factory method to allow a provider to lazily create the message body
158         * for inbound messages from other sources
159         *
160         * @return the value of the message body or null if there is no value
161         *         available
162         */
163        protected Object createBody() {
164            return null;
165        }
166    
167        public String getMessageId() {
168            if (messageId == null) {
169                messageId = createMessageId();
170            }
171            return this.messageId;
172        }
173    
174        public void setMessageId(String messageId) {
175            this.messageId = messageId;
176        }
177    
178        /**
179         * Lets allow implementations to auto-create a messageId
180         */
181        protected String createMessageId() {
182            return DEFALT_ID_GENERATOR.generateId();
183        }
184    }