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