blob: f4463d910a393e5094beaeb8b022d2abcb99eab0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import org.apache.camel.CamelContext;
import org.apache.camel.ExtendedCamelContext;
import org.apache.camel.FailedToStartRouteException;
import org.apache.camel.Route;
import org.apache.camel.impl.engine.AbstractCamelContext;
import org.apache.camel.impl.engine.DefaultRouteContext;
import org.apache.camel.model.DataFormatDefinition;
import org.apache.camel.model.HystrixConfigurationDefinition;
import org.apache.camel.model.Model;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.ProcessorDefinitionHelper;
import org.apache.camel.model.Resilience4jConfigurationDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.RouteDefinitionHelper;
import org.apache.camel.model.RouteFilters;
import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.model.transformer.TransformerDefinition;
import org.apache.camel.model.validator.ValidatorDefinition;
import org.apache.camel.reifier.RouteReifier;
import org.apache.camel.spi.RouteContext;
public class DefaultModel implements Model {
private final CamelContext camelContext;
private final List<RouteDefinition> routeDefinitions = new ArrayList<>();
private final List<RestDefinition> restDefinitions = new ArrayList<>();
private Map<String, DataFormatDefinition> dataFormats = new HashMap<>();
private List<TransformerDefinition> transformers = new ArrayList<>();
private List<ValidatorDefinition> validators = new ArrayList<>();
private Map<String, ServiceCallConfigurationDefinition> serviceCallConfigurations = new ConcurrentHashMap<>();
private Map<String, HystrixConfigurationDefinition> hystrixConfigurations = new ConcurrentHashMap<>();
private Map<String, Resilience4jConfigurationDefinition> resilience4jConfigurations = new ConcurrentHashMap<>();
private Function<RouteDefinition, Boolean> routeFilter;
public DefaultModel(CamelContext camelContext) {
this.camelContext = camelContext;
}
public CamelContext getCamelContext() {
return camelContext;
}
@Override
public synchronized void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
if (routeDefinitions == null || routeDefinitions.isEmpty()) {
return;
}
List<RouteDefinition> list = new ArrayList<>();
routeDefinitions.forEach(r -> {
if (routeFilter == null || routeFilter.apply(r)) {
list.add(r);
}
});
removeRouteDefinitions(list);
this.routeDefinitions.addAll(list);
if (shouldStartRoutes()) {
startRouteDefinitions(list);
}
}
@Override
public void addRouteDefinition(RouteDefinition routeDefinition) throws Exception {
addRouteDefinitions(Collections.singletonList(routeDefinition));
}
@Override
public synchronized void removeRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
for (RouteDefinition routeDefinition : routeDefinitions) {
removeRouteDefinition(routeDefinition);
}
}
@Override
public synchronized void removeRouteDefinition(RouteDefinition routeDefinition) throws Exception {
RouteDefinition toBeRemoved = routeDefinition;
String id = routeDefinition.getId();
if (id != null) {
// remove existing route
camelContext.getRouteController().stopRoute(id);
camelContext.removeRoute(id);
toBeRemoved = getRouteDefinition(id);
}
this.routeDefinitions.remove(toBeRemoved);
}
@Override
public synchronized List<RouteDefinition> getRouteDefinitions() {
return routeDefinitions;
}
@Override
public synchronized RouteDefinition getRouteDefinition(String id) {
for (RouteDefinition route : routeDefinitions) {
if (route.idOrCreate(camelContext.adapt(ExtendedCamelContext.class).getNodeIdFactory()).equals(id)) {
return route;
}
}
return null;
}
@Override
public synchronized List<RestDefinition> getRestDefinitions() {
return restDefinitions;
}
@Override
public synchronized void addRestDefinitions(Collection<RestDefinition> restDefinitions, boolean addToRoutes) throws Exception {
if (restDefinitions == null || restDefinitions.isEmpty()) {
return;
}
this.restDefinitions.addAll(restDefinitions);
if (addToRoutes) {
// rests are also routes so need to add them there too
for (final RestDefinition restDefinition : restDefinitions) {
List<RouteDefinition> routeDefinitions = restDefinition.asRouteDefinition(camelContext);
addRouteDefinitions(routeDefinitions);
}
}
}
@Override
public ServiceCallConfigurationDefinition getServiceCallConfiguration(String serviceName) {
if (serviceName == null) {
serviceName = "";
}
return serviceCallConfigurations.get(serviceName);
}
@Override
public void setServiceCallConfiguration(ServiceCallConfigurationDefinition configuration) {
serviceCallConfigurations.put("", configuration);
}
@Override
public void setServiceCallConfigurations(List<ServiceCallConfigurationDefinition> configurations) {
if (configurations != null) {
for (ServiceCallConfigurationDefinition configuration : configurations) {
serviceCallConfigurations.put(configuration.getId(), configuration);
}
}
}
@Override
public void addServiceCallConfiguration(String serviceName, ServiceCallConfigurationDefinition configuration) {
serviceCallConfigurations.put(serviceName, configuration);
}
@Override
public HystrixConfigurationDefinition getHystrixConfiguration(String id) {
if (id == null) {
id = "";
}
return hystrixConfigurations.get(id);
}
@Override
public void setHystrixConfiguration(HystrixConfigurationDefinition configuration) {
hystrixConfigurations.put("", configuration);
}
@Override
public void setHystrixConfigurations(List<HystrixConfigurationDefinition> configurations) {
if (configurations != null) {
for (HystrixConfigurationDefinition configuration : configurations) {
hystrixConfigurations.put(configuration.getId(), configuration);
}
}
}
@Override
public void addHystrixConfiguration(String id, HystrixConfigurationDefinition configuration) {
hystrixConfigurations.put(id, configuration);
}
@Override
public Resilience4jConfigurationDefinition getResilience4jConfiguration(String id) {
if (id == null) {
id = "";
}
return resilience4jConfigurations.get(id);
}
@Override
public void setResilience4jConfiguration(Resilience4jConfigurationDefinition configuration) {
resilience4jConfigurations.put("", configuration);
}
@Override
public void setResilience4jConfigurations(List<Resilience4jConfigurationDefinition> configurations) {
if (configurations != null) {
for (Resilience4jConfigurationDefinition configuration : configurations) {
resilience4jConfigurations.put(configuration.getId(), configuration);
}
}
}
@Override
public void addResilience4jConfiguration(String id, Resilience4jConfigurationDefinition configuration) {
resilience4jConfigurations.put(id, configuration);
}
@Override
public DataFormatDefinition resolveDataFormatDefinition(String name) {
// lookup type and create the data format from it
DataFormatDefinition type = lookup(camelContext, name, DataFormatDefinition.class);
if (type == null && getDataFormats() != null) {
type = getDataFormats().get(name);
}
return type;
}
@Override
public ProcessorDefinition getProcessorDefinition(String id) {
for (RouteDefinition route : getRouteDefinitions()) {
Iterator<ProcessorDefinition> it = ProcessorDefinitionHelper.filterTypeInOutputs(route.getOutputs(), ProcessorDefinition.class);
while (it.hasNext()) {
ProcessorDefinition proc = it.next();
if (id.equals(proc.getId())) {
return proc;
}
}
}
return null;
}
@Override
public <T extends ProcessorDefinition> T getProcessorDefinition(String id, Class<T> type) {
ProcessorDefinition answer = getProcessorDefinition(id);
if (answer != null) {
return type.cast(answer);
}
return null;
}
@Override
public void setDataFormats(Map<String, DataFormatDefinition> dataFormats) {
this.dataFormats = dataFormats;
}
@Override
public Map<String, DataFormatDefinition> getDataFormats() {
return dataFormats;
}
@Override
public void setTransformers(List<TransformerDefinition> transformers) {
this.transformers = transformers;
}
@Override
public List<TransformerDefinition> getTransformers() {
return transformers;
}
@Override
public void setValidators(List<ValidatorDefinition> validators) {
this.validators = validators;
}
@Override
public List<ValidatorDefinition> getValidators() {
return validators;
}
@Override
public void startRouteDefinitions() throws Exception {
startRouteDefinitions(routeDefinitions);
}
@Override
public void setRouteFilterPattern(String include, String exclude) {
setRouteFilter(RouteFilters.filterByPattern(include, exclude));
}
@Override
public Function<RouteDefinition, Boolean> getRouteFilter() {
return routeFilter;
}
@Override
public void setRouteFilter(Function<RouteDefinition, Boolean> routeFilter) {
this.routeFilter = routeFilter;
}
protected void startRouteDefinitions(Collection<RouteDefinition> list) throws Exception {
if (list != null) {
for (RouteDefinition route : list) {
startRoute(route);
}
}
}
public void startRoute(RouteDefinition routeDefinition) throws Exception {
prepare(routeDefinition);
start(routeDefinition);
}
protected void prepare(RouteDefinition routeDefinition) throws Exception {
// assign ids to the routes and validate that the id's is all unique
RouteDefinitionHelper.forceAssignIds(camelContext, routeDefinitions);
String duplicate = RouteDefinitionHelper.validateUniqueIds(routeDefinition, routeDefinitions);
if (duplicate != null) {
throw new FailedToStartRouteException(routeDefinition.getId(), "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes.");
}
// must ensure route is prepared, before we can start it
if (!routeDefinition.isPrepared()) {
RouteDefinitionHelper.prepareRoute(camelContext, routeDefinition);
routeDefinition.markPrepared();
}
}
protected void start(RouteDefinition routeDefinition) throws Exception {
// indicate we are staring the route using this thread so
// we are able to query this if needed
AbstractCamelContext mcc = camelContext.adapt(AbstractCamelContext.class);
mcc.setStartingRoutes(true);
try {
String id = routeDefinition.idOrCreate(camelContext.adapt(ExtendedCamelContext.class).getNodeIdFactory());
RouteContext routeContext = new DefaultRouteContext(camelContext, routeDefinition, id);
Route route = new RouteReifier(routeDefinition).createRoute(camelContext, routeContext);
RouteService routeService = new RouteService(route);
mcc.startRouteService(routeService, true);
} finally {
// we are done staring routes
mcc.setStartingRoutes(false);
}
}
/**
* Should we start newly added routes?
*/
protected boolean shouldStartRoutes() {
return camelContext.isStarted() && !camelContext.isStarting();
}
protected static <T> T lookup(CamelContext context, String ref, Class<T> type) {
try {
return context.getRegistry().lookupByNameAndType(ref, type);
} catch (Exception e) {
// need to ignore not same type and return it as null
return null;
}
}
}