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 java.util.ArrayList; 020import java.util.Collection; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.concurrent.atomic.AtomicInteger; 025 026import org.apache.camel.CamelContext; 027import org.apache.camel.Endpoint; 028import org.apache.camel.NoSuchEndpointException; 029import org.apache.camel.Processor; 030import org.apache.camel.Route; 031import org.apache.camel.RuntimeCamelException; 032import org.apache.camel.ShutdownRoute; 033import org.apache.camel.ShutdownRunningTask; 034import org.apache.camel.model.FromDefinition; 035import org.apache.camel.model.ProcessorDefinition; 036import org.apache.camel.model.PropertyDefinition; 037import org.apache.camel.model.RouteDefinition; 038import org.apache.camel.processor.CamelInternalProcessor; 039import org.apache.camel.processor.ContractAdvice; 040import org.apache.camel.processor.Pipeline; 041import org.apache.camel.spi.Contract; 042import org.apache.camel.spi.InterceptStrategy; 043import org.apache.camel.spi.RouteContext; 044import org.apache.camel.spi.RouteController; 045import org.apache.camel.spi.RouteError; 046import org.apache.camel.spi.RoutePolicy; 047import org.apache.camel.util.CamelContextHelper; 048import org.apache.camel.util.ObjectHelper; 049 050/** 051 * The context used to activate new routing rules 052 * 053 * @version 054 */ 055public class DefaultRouteContext implements RouteContext { 056 private final Map<ProcessorDefinition<?>, AtomicInteger> nodeIndex = new HashMap<>(); 057 private final RouteDefinition route; 058 private FromDefinition from; 059 private final Collection<Route> routes; 060 private Endpoint endpoint; 061 private final List<Processor> eventDrivenProcessors = new ArrayList<>(); 062 private CamelContext camelContext; 063 private List<InterceptStrategy> interceptStrategies = new ArrayList<>(); 064 private InterceptStrategy managedInterceptStrategy; 065 private boolean routeAdded; 066 private Boolean trace; 067 private Boolean messageHistory; 068 private Boolean logMask; 069 private Boolean logExhaustedMessageBody; 070 private Boolean streamCache; 071 private Boolean handleFault; 072 private Long delay; 073 private Boolean autoStartup = Boolean.TRUE; 074 private List<RoutePolicy> routePolicyList = new ArrayList<>(); 075 private ShutdownRoute shutdownRoute; 076 private ShutdownRunningTask shutdownRunningTask; 077 private RouteError routeError; 078 private RouteController routeController; 079 080 public DefaultRouteContext(CamelContext camelContext, RouteDefinition route, FromDefinition from, Collection<Route> routes) { 081 this.camelContext = camelContext; 082 this.route = route; 083 this.from = from; 084 this.routes = routes; 085 } 086 087 /** 088 * Only used for lazy construction from inside ExpressionType 089 */ 090 public DefaultRouteContext(CamelContext camelContext) { 091 this.camelContext = camelContext; 092 this.routes = new ArrayList<>(); 093 this.route = new RouteDefinition("temporary"); 094 } 095 096 public Endpoint getEndpoint() { 097 if (endpoint == null) { 098 endpoint = from.resolveEndpoint(this); 099 } 100 return endpoint; 101 } 102 103 public FromDefinition getFrom() { 104 return from; 105 } 106 107 public RouteDefinition getRoute() { 108 return route; 109 } 110 111 public CamelContext getCamelContext() { 112 return camelContext; 113 } 114 115 public Endpoint resolveEndpoint(String uri) { 116 return route.resolveEndpoint(getCamelContext(), uri); 117 } 118 119 public Endpoint resolveEndpoint(String uri, String ref) { 120 Endpoint endpoint = null; 121 if (uri != null) { 122 endpoint = resolveEndpoint(uri); 123 if (endpoint == null) { 124 throw new NoSuchEndpointException(uri); 125 } 126 } 127 if (ref != null) { 128 endpoint = lookup(ref, Endpoint.class); 129 if (endpoint == null) { 130 throw new NoSuchEndpointException("ref:" + ref, "check your camel registry with id " + ref); 131 } 132 // Check the endpoint has the right CamelContext 133 if (!this.getCamelContext().equals(endpoint.getCamelContext())) { 134 throw new NoSuchEndpointException("ref:" + ref, "make sure the endpoint has the same camel context as the route does."); 135 } 136 try { 137 // need add the endpoint into service 138 getCamelContext().addService(endpoint); 139 } catch (Exception ex) { 140 throw new RuntimeCamelException(ex); 141 } 142 } 143 if (endpoint == null) { 144 throw new IllegalArgumentException("Either 'uri' or 'ref' must be specified on: " + this); 145 } else { 146 return endpoint; 147 } 148 } 149 150 public <T> T lookup(String name, Class<T> type) { 151 return getCamelContext().getRegistry().lookupByNameAndType(name, type); 152 } 153 154 public <T> Map<String, T> lookupByType(Class<T> type) { 155 return getCamelContext().getRegistry().findByTypeWithName(type); 156 } 157 158 @Override 159 public <T> T mandatoryLookup(String name, Class<T> type) { 160 return CamelContextHelper.mandatoryLookup(getCamelContext(), name, type); 161 } 162 163 public void commit() { 164 // now lets turn all of the event driven consumer processors into a single route 165 if (!eventDrivenProcessors.isEmpty()) { 166 Processor target = Pipeline.newInstance(getCamelContext(), eventDrivenProcessors); 167 168 // force creating the route id so its known ahead of the route is started 169 String routeId = route.idOrCreate(getCamelContext().getNodeIdFactory()); 170 171 // and wrap it in a unit of work so the UoW is on the top, so the entire route will be in the same UoW 172 CamelInternalProcessor internal = new CamelInternalProcessor(target); 173 internal.addAdvice(new CamelInternalProcessor.UnitOfWorkProcessorAdvice(this)); 174 175 // and then optionally add route policy processor if a custom policy is set 176 List<RoutePolicy> routePolicyList = getRoutePolicyList(); 177 if (routePolicyList != null && !routePolicyList.isEmpty()) { 178 for (RoutePolicy policy : routePolicyList) { 179 // add policy as service if we have not already done that (eg possible if two routes have the same service) 180 // this ensures Camel can control the lifecycle of the policy 181 if (!camelContext.hasService(policy)) { 182 try { 183 camelContext.addService(policy); 184 } catch (Exception e) { 185 throw ObjectHelper.wrapRuntimeCamelException(e); 186 } 187 } 188 } 189 190 internal.addAdvice(new CamelInternalProcessor.RoutePolicyAdvice(routePolicyList)); 191 } 192 193 // wrap in route inflight processor to track number of inflight exchanges for the route 194 internal.addAdvice(new CamelInternalProcessor.RouteInflightRepositoryAdvice(camelContext.getInflightRepository(), routeId)); 195 196 // wrap in JMX instrumentation processor that is used for performance stats 197 internal.addAdvice(new CamelInternalProcessor.InstrumentationAdvice("route")); 198 199 // wrap in route lifecycle 200 internal.addAdvice(new CamelInternalProcessor.RouteLifecycleAdvice()); 201 202 // wrap in REST binding 203 if (route.getRestBindingDefinition() != null) { 204 try { 205 internal.addAdvice(route.getRestBindingDefinition().createRestBindingAdvice(this)); 206 } catch (Exception e) { 207 throw ObjectHelper.wrapRuntimeCamelException(e); 208 } 209 } 210 211 // wrap in contract 212 if (route.getInputType() != null || route.getOutputType() != null) { 213 Contract contract = new Contract(); 214 if (route.getInputType() != null) { 215 contract.setInputType(route.getInputType().getUrn()); 216 contract.setValidateInput(route.getInputType().isValidate()); 217 } 218 if (route.getOutputType() != null) { 219 contract.setOutputType(route.getOutputType().getUrn()); 220 contract.setValidateOutput(route.getOutputType().isValidate()); 221 } 222 internal.addAdvice(new ContractAdvice(contract)); 223 // make sure to enable data type as its in use when using input/output types on routes 224 camelContext.setUseDataType(true); 225 } 226 227 // and create the route that wraps the UoW 228 Route edcr = new EventDrivenConsumerRoute(this, getEndpoint(), internal); 229 edcr.getProperties().put(Route.ID_PROPERTY, routeId); 230 edcr.getProperties().put(Route.PARENT_PROPERTY, Integer.toHexString(route.hashCode())); 231 edcr.getProperties().put(Route.DESCRIPTION_PROPERTY, route.getDescriptionText()); 232 if (route.getGroup() != null) { 233 edcr.getProperties().put(Route.GROUP_PROPERTY, route.getGroup()); 234 } 235 String rest = "false"; 236 if (route.isRest() != null && route.isRest()) { 237 rest = "true"; 238 } 239 edcr.getProperties().put(Route.REST_PROPERTY, rest); 240 241 List<PropertyDefinition> properties = route.getRouteProperties(); 242 if (properties != null) { 243 final String[] reservedProperties = new String[] { 244 Route.ID_PROPERTY, 245 Route.PARENT_PROPERTY, 246 Route.GROUP_PROPERTY, 247 Route.REST_PROPERTY, 248 Route.DESCRIPTION_PROPERTY 249 }; 250 251 for (PropertyDefinition prop : properties) { 252 try { 253 final String key = CamelContextHelper.parseText(camelContext, prop.getKey()); 254 final String val = CamelContextHelper.parseText(camelContext, prop.getValue()); 255 256 for (String property : reservedProperties) { 257 if (property.equalsIgnoreCase(key)) { 258 throw new IllegalArgumentException("Cannot set route property " + property + " as it is a reserved property"); 259 } 260 } 261 262 edcr.getProperties().put(key, val); 263 } catch (Exception e) { 264 throw ObjectHelper.wrapRuntimeCamelException(e); 265 } 266 } 267 } 268 269 // after the route is created then set the route on the policy processor so we get hold of it 270 CamelInternalProcessor.RoutePolicyAdvice task = internal.getAdvice(CamelInternalProcessor.RoutePolicyAdvice.class); 271 if (task != null) { 272 task.setRoute(edcr); 273 } 274 CamelInternalProcessor.RouteLifecycleAdvice task2 = internal.getAdvice(CamelInternalProcessor.RouteLifecycleAdvice.class); 275 if (task2 != null) { 276 task2.setRoute(edcr); 277 } 278 279 // invoke init on route policy 280 if (routePolicyList != null && !routePolicyList.isEmpty()) { 281 for (RoutePolicy policy : routePolicyList) { 282 policy.onInit(edcr); 283 } 284 } 285 286 routes.add(edcr); 287 } 288 } 289 290 public void addEventDrivenProcessor(Processor processor) { 291 eventDrivenProcessors.add(processor); 292 } 293 294 public List<InterceptStrategy> getInterceptStrategies() { 295 return interceptStrategies; 296 } 297 298 public void setInterceptStrategies(List<InterceptStrategy> interceptStrategies) { 299 this.interceptStrategies = interceptStrategies; 300 } 301 302 public void addInterceptStrategy(InterceptStrategy interceptStrategy) { 303 getInterceptStrategies().add(interceptStrategy); 304 } 305 306 public void setManagedInterceptStrategy(InterceptStrategy interceptStrategy) { 307 this.managedInterceptStrategy = interceptStrategy; 308 } 309 310 public InterceptStrategy getManagedInterceptStrategy() { 311 return managedInterceptStrategy; 312 } 313 314 public boolean isRouteAdded() { 315 return routeAdded; 316 } 317 318 public void setIsRouteAdded(boolean routeAdded) { 319 this.routeAdded = routeAdded; 320 } 321 322 public void setTracing(Boolean tracing) { 323 this.trace = tracing; 324 } 325 326 public Boolean isTracing() { 327 if (trace != null) { 328 return trace; 329 } else { 330 // fallback to the option from camel context 331 return getCamelContext().isTracing(); 332 } 333 } 334 335 public void setMessageHistory(Boolean messageHistory) { 336 this.messageHistory = messageHistory; 337 } 338 339 public Boolean isMessageHistory() { 340 if (messageHistory != null) { 341 return messageHistory; 342 } else { 343 // fallback to the option from camel context 344 return getCamelContext().isMessageHistory(); 345 } 346 } 347 348 public void setLogMask(Boolean logMask) { 349 this.logMask = logMask; 350 } 351 352 public Boolean isLogMask() { 353 if (logMask != null) { 354 return logMask; 355 } else { 356 // fallback to the option from camel context 357 return getCamelContext().isLogMask(); 358 } 359 } 360 361 public void setLogExhaustedMessageBody(Boolean logExhaustedMessageBody) { 362 this.logExhaustedMessageBody = logExhaustedMessageBody; 363 } 364 365 public Boolean isLogExhaustedMessageBody() { 366 if (logExhaustedMessageBody != null) { 367 return logExhaustedMessageBody; 368 } else { 369 // fallback to the option from camel context 370 return getCamelContext().isLogExhaustedMessageBody(); 371 } 372 } 373 374 public void setStreamCaching(Boolean cache) { 375 this.streamCache = cache; 376 } 377 378 public Boolean isStreamCaching() { 379 if (streamCache != null) { 380 return streamCache; 381 } else { 382 // fallback to the option from camel context 383 return getCamelContext().isStreamCaching(); 384 } 385 } 386 387 public void setHandleFault(Boolean handleFault) { 388 this.handleFault = handleFault; 389 } 390 391 public Boolean isHandleFault() { 392 if (handleFault != null) { 393 return handleFault; 394 } else { 395 // fallback to the option from camel context 396 return getCamelContext().isHandleFault(); 397 } 398 } 399 400 public void setDelayer(Long delay) { 401 this.delay = delay; 402 } 403 404 public Long getDelayer() { 405 if (delay != null) { 406 return delay; 407 } else { 408 // fallback to the option from camel context 409 return getCamelContext().getDelayer(); 410 } 411 } 412 413 public void setAutoStartup(Boolean autoStartup) { 414 this.autoStartup = autoStartup; 415 } 416 417 public Boolean isAutoStartup() { 418 if (autoStartup != null) { 419 return autoStartup; 420 } 421 // default to true 422 return true; 423 } 424 425 public void setShutdownRoute(ShutdownRoute shutdownRoute) { 426 this.shutdownRoute = shutdownRoute; 427 } 428 429 public void setAllowUseOriginalMessage(Boolean allowUseOriginalMessage) { 430 // can only be configured on CamelContext 431 getCamelContext().setAllowUseOriginalMessage(allowUseOriginalMessage); 432 } 433 434 public Boolean isAllowUseOriginalMessage() { 435 // can only be configured on CamelContext 436 return getCamelContext().isAllowUseOriginalMessage(); 437 } 438 439 public ShutdownRoute getShutdownRoute() { 440 if (shutdownRoute != null) { 441 return shutdownRoute; 442 } else { 443 // fallback to the option from camel context 444 return getCamelContext().getShutdownRoute(); 445 } 446 } 447 448 public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) { 449 this.shutdownRunningTask = shutdownRunningTask; 450 } 451 452 public ShutdownRunningTask getShutdownRunningTask() { 453 if (shutdownRunningTask != null) { 454 return shutdownRunningTask; 455 } else { 456 // fallback to the option from camel context 457 return getCamelContext().getShutdownRunningTask(); 458 } 459 } 460 461 public int getAndIncrement(ProcessorDefinition<?> node) { 462 AtomicInteger count = nodeIndex.get(node); 463 if (count == null) { 464 count = new AtomicInteger(); 465 nodeIndex.put(node, count); 466 } 467 return count.getAndIncrement(); 468 } 469 470 public void setRoutePolicyList(List<RoutePolicy> routePolicyList) { 471 this.routePolicyList = routePolicyList; 472 } 473 474 public List<RoutePolicy> getRoutePolicyList() { 475 return routePolicyList; 476 } 477 478 @Override 479 public RouteError getLastError() { 480 return routeError; 481 } 482 483 @Override 484 public void setLastError(RouteError routeError) { 485 this.routeError = routeError; 486 } 487 488 @Override 489 public RouteController getRouteController() { 490 return routeController; 491 } 492 493 @Override 494 public void setRouteController(RouteController routeController) { 495 this.routeController = routeController; 496 } 497}