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