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