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