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