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