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 java.util.Map; 020 import java.util.concurrent.ConcurrentHashMap; 021 022 import org.apache.camel.CamelContext; 023 import org.apache.camel.Exchange; 024 import org.apache.camel.ExchangePattern; 025 import org.apache.camel.ExchangeProperty; 026 import org.apache.camel.Message; 027 import org.apache.camel.RuntimeCamelException; 028 import org.apache.camel.spi.UnitOfWork; 029 import org.apache.camel.util.UuidGenerator; 030 import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException; 031 032 /** 033 * A default implementation of {@link Exchange} 034 * 035 * @version $Revision: 1389 $ 036 */ 037 public class DefaultExchange implements Exchange { 038 039 private static final UuidGenerator DEFAULT_ID_GENERATOR = new UuidGenerator(); 040 protected final CamelContext context; 041 private Map<String, Object> properties; 042 private Message in; 043 private Message out; 044 private Message fault; 045 private Throwable exception; 046 private String exchangeId; 047 private UnitOfWork unitOfWork; 048 private ExchangePattern pattern; 049 050 public DefaultExchange(CamelContext context) { 051 this(context, ExchangePattern.InOnly); 052 } 053 054 public DefaultExchange(CamelContext context, ExchangePattern pattern) { 055 this.context = context; 056 this.pattern = pattern; 057 } 058 059 public DefaultExchange(DefaultExchange parent) { 060 this(parent.getContext(), parent.getPattern()); 061 this.unitOfWork = parent.getUnitOfWork(); 062 } 063 064 @Override 065 public String toString() { 066 return "Exchange[" + in + "]"; 067 } 068 069 public Exchange copy() { 070 Exchange exchange = newInstance(); 071 exchange.copyFrom(this); 072 return exchange; 073 } 074 075 public void copyFrom(Exchange exchange) { 076 if (exchange == this) { 077 return; 078 } 079 setProperties(safeCopy(exchange.getProperties())); 080 081 // this can cause strangeness if we copy, say, a FileMessage onto an FtpExchange with overloaded getExchange() methods etc. 082 safeCopy(getIn(), exchange, exchange.getIn()); 083 Message copyOut = exchange.getOut(false); 084 if (copyOut != null) { 085 safeCopy(getOut(true), exchange, copyOut); 086 } 087 Message copyFault = exchange.getFault(false); 088 if (copyFault != null) { 089 safeCopy(getFault(true), exchange, copyFault); 090 } 091 setException(exchange.getException()); 092 093 unitOfWork = exchange.getUnitOfWork(); 094 pattern = exchange.getPattern(); 095 } 096 097 private static void safeCopy(Message message, Exchange exchange, Message that) { 098 if (message != null) { 099 message.copyFrom(that); 100 } 101 } 102 103 private static Map<String, Object> safeCopy(Map<String, Object> properties) { 104 if (properties == null) { 105 return null; 106 } 107 return new ConcurrentHashMap<String, Object>(properties); 108 } 109 110 private static Message safeCopy(Exchange exchange, Message message) { 111 if (message == null) { 112 return null; 113 } 114 Message answer = message.copy(); 115 if (answer instanceof MessageSupport) { 116 MessageSupport messageSupport = (MessageSupport) answer; 117 messageSupport.setExchange(exchange); 118 } 119 return answer; 120 } 121 122 public Exchange newInstance() { 123 return new DefaultExchange(this); 124 } 125 126 public CamelContext getContext() { 127 return context; 128 } 129 130 public Object getProperty(String name) { 131 if (properties != null) { 132 return properties.get(name); 133 } 134 return null; 135 } 136 137 public <T> T getProperty(String name, Class<T> type) { 138 Object value = getProperty(name); 139 140 // if the property is also a well known property in ExchangeProperty then validate that the 141 // value is of the same type 142 ExchangeProperty<?> property = ExchangeProperty.getByName(name); 143 if (property != null) { 144 validateExchangePropertyIsExpectedType(property, type, value); 145 } 146 147 return getContext().getTypeConverter().convertTo(type, this, value); 148 } 149 150 public void setProperty(String name, Object value) { 151 ExchangeProperty<?> property = ExchangeProperty.getByName(name); 152 153 // if the property is also a well known property in ExchangeProperty then validate that the 154 // value is of the same type 155 if (property != null) { 156 Class type = value.getClass(); 157 validateExchangePropertyIsExpectedType(property, type, value); 158 } 159 if (value != null) { 160 // avoid the NullPointException 161 getProperties().put(name, value); 162 } else { 163 // if the value is null , we just remove the key from the map 164 if (name != null) { 165 getProperties().remove(name); 166 } 167 } 168 } 169 170 private <T> void validateExchangePropertyIsExpectedType(ExchangeProperty<?> property, Class<T> type, Object value) { 171 if (value != null && property != null && !property.type().isAssignableFrom(type)) { 172 throw new RuntimeCamelException("Type cast exception while getting an " 173 + "Exchange Property value '" + value.toString() 174 + "' on Exchange " + this 175 + " for a well known Exchange Property with these traits: " + property); 176 } 177 } 178 179 public Object removeProperty(String name) { 180 return getProperties().remove(name); 181 } 182 183 public Map<String, Object> getProperties() { 184 if (properties == null) { 185 properties = new ConcurrentHashMap<String, Object>(); 186 } 187 return properties; 188 } 189 190 public void setProperties(Map<String, Object> properties) { 191 this.properties = properties; 192 } 193 194 public Message getIn() { 195 if (in == null) { 196 in = createInMessage(); 197 configureMessage(in); 198 } 199 return in; 200 } 201 202 public void setIn(Message in) { 203 this.in = in; 204 configureMessage(in); 205 } 206 207 public Message getOut() { 208 return getOut(true); 209 } 210 211 public Message getOut(boolean lazyCreate) { 212 if (out == null && lazyCreate) { 213 out = createOutMessage(); 214 configureMessage(out); 215 } 216 return out; 217 } 218 219 public void setOut(Message out) { 220 this.out = out; 221 configureMessage(out); 222 } 223 224 public Throwable getException() { 225 return exception; 226 } 227 228 public void setException(Throwable exception) { 229 this.exception = exception; 230 } 231 232 public ExchangePattern getPattern() { 233 return pattern; 234 } 235 236 public void setPattern(ExchangePattern pattern) { 237 this.pattern = pattern; 238 } 239 240 public void throwException() throws Exception { 241 if (exception == null) { 242 return; 243 } 244 if (exception instanceof RuntimeException) { 245 throw (RuntimeException)exception; 246 } 247 if (exception instanceof Exception) { 248 throw (Exception)exception; 249 } 250 throw wrapRuntimeCamelException(exception); 251 } 252 253 public Message getFault() { 254 return getFault(true); 255 } 256 257 public Message getFault(boolean lazyCreate) { 258 if (fault == null && lazyCreate) { 259 fault = createFaultMessage(); 260 configureMessage(fault); 261 } 262 return fault; 263 } 264 265 public void setFault(Message fault) { 266 this.fault = fault; 267 configureMessage(fault); 268 } 269 270 public String getExchangeId() { 271 if (exchangeId == null) { 272 exchangeId = DefaultExchange.DEFAULT_ID_GENERATOR.generateId(); 273 } 274 return exchangeId; 275 } 276 277 public void setExchangeId(String id) { 278 this.exchangeId = id; 279 } 280 281 public boolean isFailed() { 282 Message faultMessage = getFault(false); 283 if (faultMessage != null) { 284 Object faultBody = faultMessage.getBody(); 285 if (faultBody != null) { 286 return true; 287 } 288 } 289 return getException() != null; 290 } 291 292 public boolean isTransacted() { 293 ExchangeProperty<?> property = ExchangeProperty.get("transacted"); 294 return property != null && property.get(this) == Boolean.TRUE; 295 } 296 297 public UnitOfWork getUnitOfWork() { 298 return unitOfWork; 299 } 300 301 public void setUnitOfWork(UnitOfWork unitOfWork) { 302 this.unitOfWork = unitOfWork; 303 } 304 305 /** 306 * Factory method used to lazily create the IN message 307 */ 308 protected Message createInMessage() { 309 return new DefaultMessage(); 310 } 311 312 /** 313 * Factory method to lazily create the OUT message 314 */ 315 protected Message createOutMessage() { 316 return new DefaultMessage(); 317 } 318 319 /** 320 * Factory method to lazily create the FAULT message 321 */ 322 protected Message createFaultMessage() { 323 return new DefaultMessage(); 324 } 325 326 /** 327 * Configures the message after it has been set on the exchange 328 */ 329 protected void configureMessage(Message message) { 330 if (message instanceof MessageSupport) { 331 MessageSupport messageSupport = (MessageSupport)message; 332 messageSupport.setExchange(this); 333 } 334 } 335 336 }