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