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