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 }