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}