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.Collections; 022import java.util.HashMap; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026import java.util.concurrent.ConcurrentHashMap; 027import java.util.function.Function; 028 029import org.apache.camel.CamelContext; 030import org.apache.camel.ExtendedCamelContext; 031import org.apache.camel.FailedToStartRouteException; 032import org.apache.camel.Route; 033import org.apache.camel.impl.engine.AbstractCamelContext; 034import org.apache.camel.impl.engine.DefaultRouteContext; 035import org.apache.camel.model.DataFormatDefinition; 036import org.apache.camel.model.HystrixConfigurationDefinition; 037import org.apache.camel.model.Model; 038import org.apache.camel.model.ProcessorDefinition; 039import org.apache.camel.model.ProcessorDefinitionHelper; 040import org.apache.camel.model.Resilience4jConfigurationDefinition; 041import org.apache.camel.model.RouteDefinition; 042import org.apache.camel.model.RouteDefinitionHelper; 043import org.apache.camel.model.RouteFilters; 044import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition; 045import org.apache.camel.model.rest.RestDefinition; 046import org.apache.camel.model.transformer.TransformerDefinition; 047import org.apache.camel.model.validator.ValidatorDefinition; 048import org.apache.camel.reifier.RouteReifier; 049import org.apache.camel.spi.RouteContext; 050 051public class DefaultModel implements Model { 052 053 private final CamelContext camelContext; 054 055 private final List<RouteDefinition> routeDefinitions = new ArrayList<>(); 056 private final List<RestDefinition> restDefinitions = new ArrayList<>(); 057 private Map<String, DataFormatDefinition> dataFormats = new HashMap<>(); 058 private List<TransformerDefinition> transformers = new ArrayList<>(); 059 private List<ValidatorDefinition> validators = new ArrayList<>(); 060 private Map<String, ServiceCallConfigurationDefinition> serviceCallConfigurations = new ConcurrentHashMap<>(); 061 private Map<String, HystrixConfigurationDefinition> hystrixConfigurations = new ConcurrentHashMap<>(); 062 private Map<String, Resilience4jConfigurationDefinition> resilience4jConfigurations = new ConcurrentHashMap<>(); 063 private Function<RouteDefinition, Boolean> routeFilter; 064 065 public DefaultModel(CamelContext camelContext) { 066 this.camelContext = camelContext; 067 } 068 069 public CamelContext getCamelContext() { 070 return camelContext; 071 } 072 073 @Override 074 public synchronized void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception { 075 if (routeDefinitions == null || routeDefinitions.isEmpty()) { 076 return; 077 } 078 List<RouteDefinition> list = new ArrayList<>(); 079 routeDefinitions.forEach(r -> { 080 if (routeFilter == null || routeFilter.apply(r)) { 081 list.add(r); 082 } 083 }); 084 085 removeRouteDefinitions(list); 086 this.routeDefinitions.addAll(list); 087 if (shouldStartRoutes()) { 088 startRouteDefinitions(list); 089 } 090 } 091 092 @Override 093 public void addRouteDefinition(RouteDefinition routeDefinition) throws Exception { 094 addRouteDefinitions(Collections.singletonList(routeDefinition)); 095 } 096 097 @Override 098 public synchronized void removeRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception { 099 for (RouteDefinition routeDefinition : routeDefinitions) { 100 removeRouteDefinition(routeDefinition); 101 } 102 } 103 104 @Override 105 public synchronized void removeRouteDefinition(RouteDefinition routeDefinition) throws Exception { 106 RouteDefinition toBeRemoved = routeDefinition; 107 String id = routeDefinition.getId(); 108 if (id != null) { 109 // remove existing route 110 camelContext.getRouteController().stopRoute(id); 111 camelContext.removeRoute(id); 112 toBeRemoved = getRouteDefinition(id); 113 } 114 this.routeDefinitions.remove(toBeRemoved); 115 } 116 117 @Override 118 public synchronized List<RouteDefinition> getRouteDefinitions() { 119 return routeDefinitions; 120 } 121 122 @Override 123 public synchronized RouteDefinition getRouteDefinition(String id) { 124 for (RouteDefinition route : routeDefinitions) { 125 if (route.idOrCreate(camelContext.adapt(ExtendedCamelContext.class).getNodeIdFactory()).equals(id)) { 126 return route; 127 } 128 } 129 return null; 130 } 131 132 @Override 133 public synchronized List<RestDefinition> getRestDefinitions() { 134 return restDefinitions; 135 } 136 137 @Override 138 public synchronized void addRestDefinitions(Collection<RestDefinition> restDefinitions, boolean addToRoutes) throws Exception { 139 if (restDefinitions == null || restDefinitions.isEmpty()) { 140 return; 141 } 142 143 this.restDefinitions.addAll(restDefinitions); 144 if (addToRoutes) { 145 // rests are also routes so need to add them there too 146 for (final RestDefinition restDefinition : restDefinitions) { 147 List<RouteDefinition> routeDefinitions = restDefinition.asRouteDefinition(camelContext); 148 addRouteDefinitions(routeDefinitions); 149 } 150 } 151 } 152 153 @Override 154 public ServiceCallConfigurationDefinition getServiceCallConfiguration(String serviceName) { 155 if (serviceName == null) { 156 serviceName = ""; 157 } 158 159 return serviceCallConfigurations.get(serviceName); 160 } 161 162 @Override 163 public void setServiceCallConfiguration(ServiceCallConfigurationDefinition configuration) { 164 serviceCallConfigurations.put("", configuration); 165 } 166 167 @Override 168 public void setServiceCallConfigurations(List<ServiceCallConfigurationDefinition> configurations) { 169 if (configurations != null) { 170 for (ServiceCallConfigurationDefinition configuration : configurations) { 171 serviceCallConfigurations.put(configuration.getId(), configuration); 172 } 173 } 174 } 175 176 @Override 177 public void addServiceCallConfiguration(String serviceName, ServiceCallConfigurationDefinition configuration) { 178 serviceCallConfigurations.put(serviceName, configuration); 179 } 180 181 @Override 182 public HystrixConfigurationDefinition getHystrixConfiguration(String id) { 183 if (id == null) { 184 id = ""; 185 } 186 187 return hystrixConfigurations.get(id); 188 } 189 190 @Override 191 public void setHystrixConfiguration(HystrixConfigurationDefinition configuration) { 192 hystrixConfigurations.put("", configuration); 193 } 194 195 @Override 196 public void setHystrixConfigurations(List<HystrixConfigurationDefinition> configurations) { 197 if (configurations != null) { 198 for (HystrixConfigurationDefinition configuration : configurations) { 199 hystrixConfigurations.put(configuration.getId(), configuration); 200 } 201 } 202 } 203 204 @Override 205 public void addHystrixConfiguration(String id, HystrixConfigurationDefinition configuration) { 206 hystrixConfigurations.put(id, configuration); 207 } 208 209 @Override 210 public Resilience4jConfigurationDefinition getResilience4jConfiguration(String id) { 211 if (id == null) { 212 id = ""; 213 } 214 215 return resilience4jConfigurations.get(id); 216 } 217 218 @Override 219 public void setResilience4jConfiguration(Resilience4jConfigurationDefinition configuration) { 220 resilience4jConfigurations.put("", configuration); 221 } 222 223 @Override 224 public void setResilience4jConfigurations(List<Resilience4jConfigurationDefinition> configurations) { 225 if (configurations != null) { 226 for (Resilience4jConfigurationDefinition configuration : configurations) { 227 resilience4jConfigurations.put(configuration.getId(), configuration); 228 } 229 } 230 } 231 232 @Override 233 public void addResilience4jConfiguration(String id, Resilience4jConfigurationDefinition configuration) { 234 resilience4jConfigurations.put(id, configuration); 235 } 236 237 @Override 238 public DataFormatDefinition resolveDataFormatDefinition(String name) { 239 // lookup type and create the data format from it 240 DataFormatDefinition type = lookup(camelContext, name, DataFormatDefinition.class); 241 if (type == null && getDataFormats() != null) { 242 type = getDataFormats().get(name); 243 } 244 return type; 245 } 246 247 @Override 248 public ProcessorDefinition getProcessorDefinition(String id) { 249 for (RouteDefinition route : getRouteDefinitions()) { 250 Iterator<ProcessorDefinition> it = ProcessorDefinitionHelper.filterTypeInOutputs(route.getOutputs(), ProcessorDefinition.class); 251 while (it.hasNext()) { 252 ProcessorDefinition proc = it.next(); 253 if (id.equals(proc.getId())) { 254 return proc; 255 } 256 } 257 } 258 return null; 259 } 260 261 @Override 262 public <T extends ProcessorDefinition> T getProcessorDefinition(String id, Class<T> type) { 263 ProcessorDefinition answer = getProcessorDefinition(id); 264 if (answer != null) { 265 return type.cast(answer); 266 } 267 return null; 268 } 269 270 @Override 271 public void setDataFormats(Map<String, DataFormatDefinition> dataFormats) { 272 this.dataFormats = dataFormats; 273 } 274 275 @Override 276 public Map<String, DataFormatDefinition> getDataFormats() { 277 return dataFormats; 278 } 279 280 @Override 281 public void setTransformers(List<TransformerDefinition> transformers) { 282 this.transformers = transformers; 283 } 284 285 @Override 286 public List<TransformerDefinition> getTransformers() { 287 return transformers; 288 } 289 290 @Override 291 public void setValidators(List<ValidatorDefinition> validators) { 292 this.validators = validators; 293 } 294 295 @Override 296 public List<ValidatorDefinition> getValidators() { 297 return validators; 298 } 299 300 @Override 301 public void startRouteDefinitions() throws Exception { 302 startRouteDefinitions(routeDefinitions); 303 } 304 305 @Override 306 public void setRouteFilterPattern(String include, String exclude) { 307 setRouteFilter(RouteFilters.filterByPattern(include, exclude)); 308 } 309 310 @Override 311 public Function<RouteDefinition, Boolean> getRouteFilter() { 312 return routeFilter; 313 } 314 315 @Override 316 public void setRouteFilter(Function<RouteDefinition, Boolean> routeFilter) { 317 this.routeFilter = routeFilter; 318 } 319 320 protected void startRouteDefinitions(Collection<RouteDefinition> list) throws Exception { 321 if (list != null) { 322 for (RouteDefinition route : list) { 323 startRoute(route); 324 } 325 } 326 } 327 328 public void startRoute(RouteDefinition routeDefinition) throws Exception { 329 prepare(routeDefinition); 330 start(routeDefinition); 331 } 332 333 protected void prepare(RouteDefinition routeDefinition) throws Exception { 334 // assign ids to the routes and validate that the id's is all unique 335 RouteDefinitionHelper.forceAssignIds(camelContext, routeDefinitions); 336 String duplicate = RouteDefinitionHelper.validateUniqueIds(routeDefinition, routeDefinitions); 337 if (duplicate != null) { 338 throw new FailedToStartRouteException(routeDefinition.getId(), "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes."); 339 } 340 341 // must ensure route is prepared, before we can start it 342 if (!routeDefinition.isPrepared()) { 343 RouteDefinitionHelper.prepareRoute(camelContext, routeDefinition); 344 routeDefinition.markPrepared(); 345 } 346 } 347 348 protected void start(RouteDefinition routeDefinition) throws Exception { 349 // indicate we are staring the route using this thread so 350 // we are able to query this if needed 351 AbstractCamelContext mcc = camelContext.adapt(AbstractCamelContext.class); 352 mcc.setStartingRoutes(true); 353 try { 354 String id = routeDefinition.idOrCreate(camelContext.adapt(ExtendedCamelContext.class).getNodeIdFactory()); 355 RouteContext routeContext = new DefaultRouteContext(camelContext, routeDefinition, id); 356 Route route = new RouteReifier(routeContext, routeDefinition).createRoute(); 357 RouteService routeService = new RouteService(route); 358 mcc.startRouteService(routeService, true); 359 } finally { 360 // we are done staring routes 361 mcc.setStartingRoutes(false); 362 } 363 } 364 365 /** 366 * Should we start newly added routes? 367 */ 368 protected boolean shouldStartRoutes() { 369 return camelContext.isStarted() && !camelContext.isStarting(); 370 } 371 372 protected static <T> T lookup(CamelContext context, String ref, Class<T> type) { 373 try { 374 return context.getRegistry().lookupByNameAndType(ref, type); 375 } catch (Exception e) { 376 // need to ignore not same type and return it as null 377 return null; 378 } 379 } 380 381}