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.CamelContext; 020import org.apache.camel.CamelContextAware; 021import org.apache.camel.Exchange; 022import org.apache.camel.InvalidPayloadException; 023import org.apache.camel.Message; 024import org.apache.camel.TypeConverter; 025import org.apache.camel.spi.DataType; 026import org.apache.camel.spi.DataTypeAware; 027 028/** 029 * A base class for implementation inheritance providing the core 030 * {@link Message} body handling features but letting the derived class deal 031 * with headers. 032 * 033 * Unless a specific provider wishes to do something particularly clever with 034 * headers you probably want to just derive from {@link DefaultMessage} 035 * 036 * @version 037 */ 038public abstract class MessageSupport implements Message, CamelContextAware, DataTypeAware { 039 private CamelContext camelContext; 040 private Exchange exchange; 041 private Object body; 042 private String messageId; 043 private DataType dataType; 044 045 @Override 046 public String toString() { 047 // do not output information about the message as it may contain sensitive information 048 return String.format("Message[%s]", messageId == null ? "" : messageId); 049 } 050 051 @Override 052 public Object getBody() { 053 if (body == null) { 054 body = createBody(); 055 } 056 return body; 057 } 058 059 @Override 060 public <T> T getBody(Class<T> type) { 061 return getBody(type, getBody()); 062 } 063 064 @Override 065 public Object getMandatoryBody() throws InvalidPayloadException { 066 Object answer = getBody(); 067 if (answer == null) { 068 throw new InvalidPayloadException(getExchange(), Object.class, this); 069 } 070 return answer; 071 } 072 073 protected <T> T getBody(Class<T> type, Object body) { 074 // eager same instance type test to avoid the overhead of invoking the type converter 075 // if already same type 076 if (type.isInstance(body)) { 077 return type.cast(body); 078 } 079 080 Exchange e = getExchange(); 081 if (e != null) { 082 TypeConverter converter = e.getContext().getTypeConverter(); 083 084 // lets first try converting the body itself first 085 // as for some types like InputStream v Reader its more efficient to do the transformation 086 // from the body itself as its got efficient implementations of them, before trying the message 087 T answer = converter.convertTo(type, e, body); 088 if (answer != null) { 089 return answer; 090 } 091 092 // fallback and try the message itself (e.g. used in camel-http) 093 answer = converter.tryConvertTo(type, e, this); 094 if (answer != null) { 095 return answer; 096 } 097 } 098 099 // not possible to convert 100 return null; 101 } 102 103 @Override 104 public <T> T getMandatoryBody(Class<T> type) throws InvalidPayloadException { 105 // eager same instance type test to avoid the overhead of invoking the type converter 106 // if already same type 107 if (type.isInstance(body)) { 108 return type.cast(body); 109 } 110 111 Exchange e = getExchange(); 112 if (e != null) { 113 TypeConverter converter = e.getContext().getTypeConverter(); 114 try { 115 return converter.mandatoryConvertTo(type, e, getBody()); 116 } catch (Exception cause) { 117 throw new InvalidPayloadException(e, type, this, cause); 118 } 119 } 120 throw new InvalidPayloadException(e, type, this); 121 } 122 123 @Override 124 public void setBody(Object body) { 125 this.body = body; 126 // set data type if in use 127 if (body != null && camelContext != null && camelContext.isUseDataType()) { 128 this.dataType = new DataType(body.getClass()); 129 } 130 } 131 132 @Override 133 public <T> void setBody(Object value, Class<T> type) { 134 Exchange e = getExchange(); 135 if (e != null) { 136 T v = e.getContext().getTypeConverter().convertTo(type, e, value); 137 if (v != null) { 138 value = v; 139 } 140 } 141 setBody(value); 142 } 143 144 @Override 145 public void setBody(Object body, DataType type) { 146 this.body = body; 147 this.dataType = type; 148 } 149 150 @Override 151 public DataType getDataType() { 152 return this.dataType; 153 } 154 155 @Override 156 public void setDataType(DataType type) { 157 this.dataType = type; 158 } 159 160 @Override 161 public boolean hasDataType() { 162 return dataType != null; 163 } 164 165 @Override 166 public Message copy() { 167 Message answer = newInstance(); 168 // must copy over CamelContext 169 if (answer instanceof CamelContextAware) { 170 ((CamelContextAware) answer).setCamelContext(getCamelContext()); 171 } 172 answer.copyFrom(this); 173 return answer; 174 } 175 176 @Override 177 public void copyFrom(Message that) { 178 if (that == this) { 179 // the same instance so do not need to copy 180 return; 181 } 182 183 // must copy over CamelContext 184 if (that instanceof CamelContextAware) { 185 setCamelContext(((CamelContextAware) that).getCamelContext()); 186 } 187 if (that instanceof DataTypeAware && ((DataTypeAware) that).hasDataType()) { 188 setDataType(((DataTypeAware)that).getDataType()); 189 } 190 191 copyFromWithNewBody(that, that.getBody()); 192 } 193 194 @Override 195 public void copyFromWithNewBody(Message that, Object newBody) { 196 if (that == this) { 197 // the same instance so do not need to copy 198 return; 199 } 200 201 // must copy over CamelContext 202 if (that instanceof CamelContextAware) { 203 setCamelContext(((CamelContextAware) that).getCamelContext()); 204 } 205 // should likely not set DataType as the new body may be a different type than the original body 206 207 setMessageId(that.getMessageId()); 208 setBody(newBody); 209 setFault(that.isFault()); 210 211 // the headers may be the same instance if the end user has made some mistake 212 // and set the OUT message with the same header instance of the IN message etc 213 boolean sameHeadersInstance = false; 214 if (hasHeaders() && that.hasHeaders() && getHeaders() == that.getHeaders()) { 215 sameHeadersInstance = true; 216 } 217 218 if (!sameHeadersInstance) { 219 if (hasHeaders()) { 220 // okay its safe to clear the headers 221 getHeaders().clear(); 222 } 223 if (that.hasHeaders()) { 224 getHeaders().putAll(that.getHeaders()); 225 } 226 } 227 228 copyAttachments(that); 229 } 230 231 @Override 232 public Exchange getExchange() { 233 return exchange; 234 } 235 236 public void setExchange(Exchange exchange) { 237 this.exchange = exchange; 238 } 239 240 @Override 241 public CamelContext getCamelContext() { 242 return camelContext; 243 } 244 245 @Override 246 public void setCamelContext(CamelContext camelContext) { 247 this.camelContext = camelContext; 248 } 249 250 @Override 251 public void copyAttachments(Message that) { 252 // the attachments may be the same instance if the end user has made some mistake 253 // and set the OUT message with the same attachment instance of the IN message etc 254 boolean sameAttachments = false; 255 if (hasAttachments() && that.hasAttachments() && getAttachmentObjects() == that.getAttachmentObjects()) { 256 sameAttachments = true; 257 } 258 259 if (!sameAttachments) { 260 if (hasAttachments()) { 261 // okay its safe to clear the attachments 262 getAttachmentObjects().clear(); 263 } 264 if (that.hasAttachments()) { 265 getAttachmentObjects().putAll(that.getAttachmentObjects()); 266 } 267 } 268 } 269 270 /** 271 * Returns a new instance 272 */ 273 public abstract Message newInstance(); 274 275 /** 276 * A factory method to allow a provider to lazily create the message body 277 * for inbound messages from other sources 278 * 279 * @return the value of the message body or null if there is no value 280 * available 281 */ 282 protected Object createBody() { 283 return null; 284 } 285 286 @Override 287 public String getMessageId() { 288 if (messageId == null) { 289 messageId = createMessageId(); 290 } 291 return this.messageId; 292 } 293 294 @Override 295 public void setMessageId(String messageId) { 296 this.messageId = messageId; 297 } 298 299 /** 300 * Allow implementations to auto-create a messageId 301 */ 302 protected String createMessageId() { 303 String uuid = null; 304 if (exchange != null) { 305 uuid = exchange.getContext().getUuidGenerator().generateUuid(); 306 } 307 // fall back to the simple UUID generator 308 if (uuid == null) { 309 uuid = new SimpleUuidGenerator().generateUuid(); 310 } 311 return uuid; 312 } 313}