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 */
017package org.apache.camel.impl;
018
019import org.apache.camel.Exchange;
020import org.apache.camel.InvalidPayloadException;
021import org.apache.camel.Message;
022import org.apache.camel.TypeConverter;
023
024/**
025 * A base class for implementation inheritance providing the core
026 * {@link Message} body handling features but letting the derived class deal
027 * with headers.
028 *
029 * Unless a specific provider wishes to do something particularly clever with
030 * headers you probably want to just derive from {@link DefaultMessage}
031 *
032 * @version 
033 */
034public abstract class MessageSupport implements Message {
035    private Exchange exchange;
036    private Object body;
037    private String messageId;
038
039    public Object getBody() {
040        if (body == null) {
041            body = createBody();
042        }
043        return body;
044    }
045
046    public <T> T getBody(Class<T> type) {
047        return getBody(type, getBody());
048    }
049
050    public Object getMandatoryBody() throws InvalidPayloadException {
051        Object answer = getBody();
052        if (answer == null) {
053            throw new InvalidPayloadException(getExchange(), Object.class, this);
054        }
055        return answer;
056    }
057
058    protected <T> T getBody(Class<T> type, Object body) {
059        // eager same instance type test to avoid the overhead of invoking the type converter
060        // if already same type
061        if (type.isInstance(body)) {
062            return type.cast(body);
063        }
064
065        Exchange e = getExchange();
066        if (e != null) {
067            TypeConverter converter = e.getContext().getTypeConverter();
068
069            // lets first try converting the body itself first
070            // as for some types like InputStream v Reader its more efficient to do the transformation
071            // from the body itself as its got efficient implementations of them, before trying the message
072            T answer = converter.convertTo(type, e, body);
073            if (answer != null) {
074                return answer;
075            }
076
077            // fallback and try the message itself (e.g. used in camel-http)
078            answer = converter.tryConvertTo(type, e, this);
079            if (answer != null) {
080                return answer;
081            }
082        }
083
084        // not possible to convert
085        return null;
086    }
087
088    public <T> T getMandatoryBody(Class<T> type) throws InvalidPayloadException {
089        // eager same instance type test to avoid the overhead of invoking the type converter
090        // if already same type
091        if (type.isInstance(body)) {
092            return type.cast(body);
093        }
094
095        Exchange e = getExchange();
096        if (e != null) {
097            TypeConverter converter = e.getContext().getTypeConverter();
098            try {
099                return converter.mandatoryConvertTo(type, e, getBody());
100            } catch (Exception cause) {
101                throw new InvalidPayloadException(e, type, this, cause);
102            }
103        }
104        throw new InvalidPayloadException(e, type, this);
105    }
106
107    public void setBody(Object body) {
108        this.body = body;
109    }
110
111    public <T> void setBody(Object value, Class<T> type) {
112        Exchange e = getExchange();
113        if (e != null) {
114            T v = e.getContext().getTypeConverter().convertTo(type, e, value);
115            if (v != null) {
116                value = v;
117            }
118        }
119        setBody(value);
120    }
121
122    public Message copy() {
123        Message answer = newInstance();
124        answer.copyFrom(this);
125        return answer;
126    }
127
128    public void copyFrom(Message that) {
129        if (that == this) {
130            // the same instance so do not need to copy
131            return;
132        }
133
134        setMessageId(that.getMessageId());
135        setBody(that.getBody());
136        setFault(that.isFault());
137
138        // the headers may be the same instance if the end user has made some mistake
139        // and set the OUT message with the same header instance of the IN message etc
140        boolean sameHeadersInstance = false;
141        if (hasHeaders() && that.hasHeaders() && getHeaders() == that.getHeaders()) {
142            sameHeadersInstance = true;
143        }
144
145        if (!sameHeadersInstance) {
146            if (hasHeaders()) {
147                // okay its safe to clear the headers
148                getHeaders().clear();
149            }
150            if (that.hasHeaders()) {
151                getHeaders().putAll(that.getHeaders());
152            }
153        }
154
155        copyAttachments(that);
156    }
157
158    public Exchange getExchange() {
159        return exchange;
160    }
161
162    public void setExchange(Exchange exchange) {
163        this.exchange = exchange;
164    }
165    
166    public void copyAttachments(Message that) {
167        // the attachments may be the same instance if the end user has made some mistake
168        // and set the OUT message with the same attachment instance of the IN message etc
169        boolean sameAttachments = false;
170        if (hasAttachments() && that.hasAttachments() && getAttachments() == that.getAttachments()) {
171            sameAttachments = true;
172        }
173
174        if (!sameAttachments) {
175            if (hasAttachments()) {
176                // okay its safe to clear the attachments
177                getAttachments().clear();
178            }
179            if (that.hasAttachments()) {
180                getAttachments().putAll(that.getAttachments());
181            }
182        }
183    }
184
185    /**
186     * Returns a new instance
187     */
188    public abstract Message newInstance();
189
190    /**
191     * A factory method to allow a provider to lazily create the message body
192     * for inbound messages from other sources
193     *
194     * @return the value of the message body or null if there is no value
195     *         available
196     */
197    protected Object createBody() {
198        return null;
199    }
200
201    public String getMessageId() {
202        if (messageId == null) {
203            messageId = createMessageId();
204        }
205        return this.messageId;
206    }
207
208    public void setMessageId(String messageId) {
209        this.messageId = messageId;
210    }
211
212    /**
213     * Allow implementations to auto-create a messageId
214     */
215    protected String createMessageId() {
216        String uuid = null;
217        if (exchange != null) {
218            uuid = exchange.getContext().getUuidGenerator().generateUuid();
219        }
220        // fall back to the simple UUID generator
221        if (uuid == null) {
222            uuid = new SimpleUuidGenerator().generateUuid();
223        }
224        return uuid;
225    }
226}