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.model;
018
019import java.util.ArrayList;
020import java.util.List;
021import javax.xml.bind.annotation.XmlAccessType;
022import javax.xml.bind.annotation.XmlAccessorType;
023import javax.xml.bind.annotation.XmlAttribute;
024import javax.xml.bind.annotation.XmlRootElement;
025
026import org.apache.camel.ExchangePattern;
027import org.apache.camel.Expression;
028import org.apache.camel.NoSuchLanguageException;
029import org.apache.camel.Processor;
030import org.apache.camel.builder.ExpressionBuilder;
031import org.apache.camel.processor.SendDynamicProcessor;
032import org.apache.camel.spi.Language;
033import org.apache.camel.spi.Metadata;
034import org.apache.camel.spi.RouteContext;
035import org.apache.camel.util.ObjectHelper;
036
037/**
038 * Sends the message to a dynamic endpoint
039 * <p/>
040 * You can specify multiple languages in the uri separated by the plus sign, such as <tt>mock:+language:xpath:/order/@uri</tt>
041 * where <tt>mock:</tt> would be a prefix to a xpath expression.
042 * <p/>
043 * For more dynamic behavior use <a href="http://camel.apache.org/recipient-list.html">Recipient List</a> or
044 * <a href="http://camel.apache.org/dynamic-router.html">Dynamic Router</a> EIP instead.
045 */
046@Metadata(label = "eip,endpoint,routing")
047@XmlRootElement(name = "toD")
048@XmlAccessorType(XmlAccessType.FIELD)
049public class ToDynamicDefinition extends NoOutputDefinition<ToDynamicDefinition> {
050    @XmlAttribute @Metadata(required = "true")
051    private String uri;
052    @XmlAttribute
053    private ExchangePattern pattern;
054    @XmlAttribute
055    private Integer cacheSize;
056    @XmlAttribute
057    private Boolean ignoreInvalidEndpoint;
058
059    public ToDynamicDefinition() {
060    }
061
062    public ToDynamicDefinition(String uri) {
063        this.uri = uri;
064    }
065
066    @Override
067    public Processor createProcessor(RouteContext routeContext) throws Exception {
068        ObjectHelper.notEmpty(uri, "uri", this);
069
070        Expression exp = createExpression(routeContext);
071
072        SendDynamicProcessor processor = new SendDynamicProcessor(uri, exp);
073        processor.setCamelContext(routeContext.getCamelContext());
074        processor.setPattern(pattern);
075        if (cacheSize != null) {
076            processor.setCacheSize(cacheSize);
077        }
078        if (ignoreInvalidEndpoint != null) {
079            processor.setIgnoreInvalidEndpoint(ignoreInvalidEndpoint);
080        }
081        return processor;
082    }
083
084    protected Expression createExpression(RouteContext routeContext) {
085        List<Expression> list = new ArrayList<Expression>();
086        String[] parts = uri.split("\\+");
087        for (String part : parts) {
088            // the part may have optional language to use, so you can mix languages
089            String value = ObjectHelper.after(part, "language:");
090            if (value != null) {
091                String before = ObjectHelper.before(value, ":");
092                String after = ObjectHelper.after(value, ":");
093                if (before != null && after != null) {
094                    // maybe its a language, must have language: as prefix
095                    try {
096                        Language partLanguage = routeContext.getCamelContext().resolveLanguage(before);
097                        if (partLanguage != null) {
098                            Expression exp = partLanguage.createExpression(after);
099                            list.add(exp);
100                            continue;
101                        }
102                    } catch (NoSuchLanguageException e) {
103                        // ignore
104                    }
105                }
106            }
107            // fallback and use simple language
108            Language lan = routeContext.getCamelContext().resolveLanguage("simple");
109            Expression exp = lan.createExpression(part);
110            list.add(exp);
111        }
112
113        Expression exp;
114        if (list.size() == 1) {
115            exp = list.get(0);
116        } else {
117            exp = ExpressionBuilder.concatExpression(list);
118        }
119
120        return exp;
121    }
122
123    @Override
124    public String toString() {
125        return "DynamicTo[" + getLabel() + "]";
126    }
127
128    // Fluent API
129    // -------------------------------------------------------------------------
130
131    /**
132     * Sets the optional {@link ExchangePattern} used to invoke this endpoint
133     */
134    public ToDynamicDefinition pattern(ExchangePattern pattern) {
135        setPattern(pattern);
136        return this;
137    }
138
139    /**
140     * Sets the maximum size used by the {@link org.apache.camel.impl.ConsumerCache} which is used to cache and reuse producers.
141     *
142     * @param cacheSize  the cache size, use <tt>0</tt> for default cache size, or <tt>-1</tt> to turn cache off.
143     * @return the builder
144     */
145    public ToDynamicDefinition cacheSize(int cacheSize) {
146        setCacheSize(cacheSize);
147        return this;
148    }
149
150    /**
151     * Ignore the invalidate endpoint exception when try to create a producer with that endpoint
152     *
153     * @return the builder
154     */
155    public ToDynamicDefinition ignoreInvalidEndpoint() {
156        setIgnoreInvalidEndpoint(true);
157        return this;
158    }
159
160    // Properties
161    // -------------------------------------------------------------------------
162
163    public String getUri() {
164        return uri;
165    }
166
167    /**
168     * The uri of the endpoint to send to. The uri can be dynamic computed using the {@link org.apache.camel.language.simple.SimpleLanguage} expression.
169     */
170    public void setUri(String uri) {
171        this.uri = uri;
172    }
173
174    public ExchangePattern getPattern() {
175        return pattern;
176    }
177
178    public void setPattern(ExchangePattern pattern) {
179        this.pattern = pattern;
180    }
181
182    public Integer getCacheSize() {
183        return cacheSize;
184    }
185
186    public void setCacheSize(Integer cacheSize) {
187        this.cacheSize = cacheSize;
188    }
189
190    public Boolean getIgnoreInvalidEndpoint() {
191        return ignoreInvalidEndpoint;
192    }
193
194    public void setIgnoreInvalidEndpoint(Boolean ignoreInvalidEndpoint) {
195        this.ignoreInvalidEndpoint = ignoreInvalidEndpoint;
196    }
197
198
199}