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