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 // cover over exchange if none has been assigned 191 if (getExchange() == null) { 192 setExchange(that.getExchange()); 193 } 194 195 copyFromWithNewBody(that, that.getBody()); 196 } 197 198 @Override 199 public void copyFromWithNewBody(Message that, Object newBody) { 200 if (that == this) { 201 // the same instance so do not need to copy 202 return; 203 } 204 205 // must copy over CamelContext 206 if (that instanceof CamelContextAware) { 207 setCamelContext(((CamelContextAware) that).getCamelContext()); 208 } 209 // cover over exchange if none has been assigned 210 if (getExchange() == null) { 211 setExchange(that.getExchange()); 212 } 213 214 // should likely not set DataType as the new body may be a different type than the original body 215 216 setMessageId(that.getMessageId()); 217 setBody(newBody); 218 setFault(that.isFault()); 219 220 // the headers may be the same instance if the end user has made some mistake 221 // and set the OUT message with the same header instance of the IN message etc 222 boolean sameHeadersInstance = false; 223 if (hasHeaders() && that.hasHeaders() && getHeaders() == that.getHeaders()) { 224 sameHeadersInstance = true; 225 } 226 227 if (!sameHeadersInstance) { 228 if (hasHeaders()) { 229 // okay its safe to clear the headers 230 getHeaders().clear(); 231 } 232 if (that.hasHeaders()) { 233 getHeaders().putAll(that.getHeaders()); 234 } 235 } 236 237 copyAttachments(that); 238 } 239 240 @Override 241 public Exchange getExchange() { 242 return exchange; 243 } 244 245 public void setExchange(Exchange exchange) { 246 this.exchange = exchange; 247 } 248 249 @Override 250 public CamelContext getCamelContext() { 251 return camelContext; 252 } 253 254 @Override 255 public void setCamelContext(CamelContext camelContext) { 256 this.camelContext = camelContext; 257 } 258 259 @Override 260 public void copyAttachments(Message that) { 261 // the attachments may be the same instance if the end user has made some mistake 262 // and set the OUT message with the same attachment instance of the IN message etc 263 boolean sameAttachments = false; 264 if (hasAttachments() && that.hasAttachments() && getAttachmentObjects() == that.getAttachmentObjects()) { 265 sameAttachments = true; 266 } 267 268 if (!sameAttachments) { 269 if (hasAttachments()) { 270 // okay its safe to clear the attachments 271 getAttachmentObjects().clear(); 272 } 273 if (that.hasAttachments()) { 274 getAttachmentObjects().putAll(that.getAttachmentObjects()); 275 } 276 } 277 } 278 279 /** 280 * Returns a new instance 281 */ 282 public abstract Message newInstance(); 283 284 /** 285 * A factory method to allow a provider to lazily create the message body 286 * for inbound messages from other sources 287 * 288 * @return the value of the message body or null if there is no value 289 * available 290 */ 291 protected Object createBody() { 292 return null; 293 } 294 295 @Override 296 public String getMessageId() { 297 if (messageId == null) { 298 messageId = createMessageId(); 299 } 300 return this.messageId; 301 } 302 303 @Override 304 public void setMessageId(String messageId) { 305 this.messageId = messageId; 306 } 307 308 /** 309 * Allow implementations to auto-create a messageId 310 */ 311 protected String createMessageId() { 312 String uuid = null; 313 if (exchange != null) { 314 uuid = exchange.getContext().getUuidGenerator().generateUuid(); 315 } 316 // fall back to the simple UUID generator 317 if (uuid == null) { 318 uuid = new SimpleUuidGenerator().generateUuid(); 319 } 320 return uuid; 321 } 322}