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.reifier;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import org.apache.camel.ExchangePattern;
023import org.apache.camel.Expression;
024import org.apache.camel.NoSuchLanguageException;
025import org.apache.camel.Processor;
026import org.apache.camel.Route;
027import org.apache.camel.builder.ExpressionBuilder;
028import org.apache.camel.model.ProcessorDefinition;
029import org.apache.camel.model.ToDynamicDefinition;
030import org.apache.camel.processor.SendDynamicProcessor;
031import org.apache.camel.spi.Language;
032import org.apache.camel.spi.PropertiesComponent;
033import org.apache.camel.util.Pair;
034import org.apache.camel.util.StringHelper;
035import org.apache.camel.util.URISupport;
036
037public class ToDynamicReifier<T extends ToDynamicDefinition> extends ProcessorReifier<T> {
038
039    public ToDynamicReifier(Route route, ProcessorDefinition<?> definition) {
040        super(route, (T) definition);
041    }
042
043    @Override
044    public Processor createProcessor() throws Exception {
045        String uri;
046        Expression exp;
047        if (definition.getEndpointProducerBuilder() != null) {
048            uri = definition.getEndpointProducerBuilder().getUri();
049            exp = definition.getEndpointProducerBuilder().expr(camelContext);
050        } else {
051            uri = StringHelper.notEmpty(definition.getUri(), "uri", this);
052            exp = createExpression(uri);
053        }
054
055        SendDynamicProcessor processor = new SendDynamicProcessor(uri, exp);
056        processor.setCamelContext(camelContext);
057        processor.setPattern(parse(ExchangePattern.class, definition.getPattern()));
058        if (definition.getCacheSize() != null) {
059            processor.setCacheSize(parseInt(definition.getCacheSize()));
060        }
061        if (definition.getIgnoreInvalidEndpoint() != null) {
062            processor.setIgnoreInvalidEndpoint(parseBoolean(definition.getIgnoreInvalidEndpoint(), false));
063        }
064        if  (definition.getAllowOptimisedComponents() != null) {
065            processor.setAllowOptimisedComponents(parseBoolean(definition.getAllowOptimisedComponents(), true));
066        }
067        if  (definition.getAutoStartComponents() != null) {
068            processor.setAutoStartupComponents(parseBoolean(definition.getAutoStartComponents(), true));
069        }
070        return processor;
071    }
072
073    protected Expression createExpression(String uri) {
074        List<Expression> list = new ArrayList<>();
075
076        // make sure to parse property placeholders
077        uri = camelContext.resolvePropertyPlaceholders(uri);
078
079        String[] parts = safeSplitRaw(uri);
080        for (String part : parts) {
081            // the part may have optional language to use, so you can mix
082            // languages
083            String value = StringHelper.after(part, "language:");
084            if (value != null) {
085                String before = StringHelper.before(value, ":");
086                String after = StringHelper.after(value, ":");
087                if (before != null && after != null) {
088                    // maybe its a language, must have language: as prefix
089                    try {
090                        Language partLanguage = camelContext.resolveLanguage(before);
091                        if (partLanguage != null) {
092                            Expression exp = partLanguage.createExpression(after);
093                            list.add(exp);
094                            continue;
095                        }
096                    } catch (NoSuchLanguageException e) {
097                        // ignore
098                    }
099                }
100            }
101
102            // fallback and use simple language
103            Language lan = camelContext.resolveLanguage("simple");
104            Expression exp = lan.createExpression(part);
105            list.add(exp);
106        }
107
108        Expression exp;
109        if (list.size() == 1) {
110            exp = list.get(0);
111        } else {
112            exp = ExpressionBuilder.concatExpression(list);
113        }
114
115        return exp;
116    }
117
118    // Utilities
119    // -------------------------------------------------------------------------
120
121    /**
122     * We need to split the string safely for each + sign, but avoid splitting
123     * within RAW(...).
124     */
125    private static String[] safeSplitRaw(String s) {
126        List<String> list = new ArrayList<>();
127
128        if (!s.contains("+")) {
129            // no plus sign so there is only one part, so no need to split
130            list.add(s);
131        } else {
132            // there is a plus sign so we need to split in a safe manner
133            List<Pair<Integer>> rawPairs = URISupport.scanRaw(s);
134            StringBuilder sb = new StringBuilder();
135            char[] chars = s.toCharArray();
136            for (int i = 0; i < chars.length; i++) {
137                char ch = chars[i];
138                if (ch != '+' || URISupport.isRaw(i, rawPairs)) {
139                    sb.append(ch);
140                } else {
141                    list.add(sb.toString());
142                    sb.setLength(0);
143                }
144            }
145            // any leftover?
146            if (sb.length() > 0) {
147                list.add(sb.toString());
148                sb.setLength(0);
149            }
150        }
151
152        return list.toArray(new String[list.size()]);
153    }
154
155}