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.language; 018 019import java.util.LinkedHashMap; 020import java.util.Map; 021import java.util.function.BiFunction; 022 023import org.apache.camel.AfterPropertiesConfigured; 024import org.apache.camel.CamelContext; 025import org.apache.camel.CamelContextAware; 026import org.apache.camel.Expression; 027import org.apache.camel.NoSuchLanguageException; 028import org.apache.camel.Predicate; 029import org.apache.camel.model.ExpressionSubElementDefinition; 030import org.apache.camel.model.language.ConstantExpression; 031import org.apache.camel.model.language.ExchangePropertyExpression; 032import org.apache.camel.model.language.ExpressionDefinition; 033import org.apache.camel.model.language.GroovyExpression; 034import org.apache.camel.model.language.HeaderExpression; 035import org.apache.camel.model.language.Hl7TerserExpression; 036import org.apache.camel.model.language.JsonPathExpression; 037import org.apache.camel.model.language.LanguageExpression; 038import org.apache.camel.model.language.MethodCallExpression; 039import org.apache.camel.model.language.MvelExpression; 040import org.apache.camel.model.language.OgnlExpression; 041import org.apache.camel.model.language.RefExpression; 042import org.apache.camel.model.language.SimpleExpression; 043import org.apache.camel.model.language.SpELExpression; 044import org.apache.camel.model.language.TokenizerExpression; 045import org.apache.camel.model.language.XMLTokenizerExpression; 046import org.apache.camel.model.language.XPathExpression; 047import org.apache.camel.model.language.XQueryExpression; 048import org.apache.camel.reifier.AbstractReifier; 049import org.apache.camel.spi.Language; 050import org.apache.camel.spi.PropertyConfigurer; 051import org.apache.camel.spi.PropertyConfigurerAware; 052import org.apache.camel.spi.ReifierStrategy; 053import org.apache.camel.support.ExpressionToPredicateAdapter; 054import org.apache.camel.support.PropertyBindingSupport; 055import org.apache.camel.support.ScriptHelper; 056import org.apache.camel.util.ObjectHelper; 057 058public class ExpressionReifier<T extends ExpressionDefinition> extends AbstractReifier { 059 060 private static final Map<Class<?>, BiFunction<CamelContext, ExpressionDefinition, ExpressionReifier<? extends ExpressionDefinition>>> EXPRESSIONS; 061 062 static { 063 Map<Class<?>, BiFunction<CamelContext, ExpressionDefinition, ExpressionReifier<? extends ExpressionDefinition>>> map = new LinkedHashMap<>(); 064 map.put(ConstantExpression.class, ExpressionReifier::new); 065 map.put(ExchangePropertyExpression.class, ExpressionReifier::new); 066 map.put(ExpressionDefinition.class, ExpressionReifier::new); 067 map.put(GroovyExpression.class, ExpressionReifier::new); 068 map.put(HeaderExpression.class, ExpressionReifier::new); 069 map.put(Hl7TerserExpression.class, ExpressionReifier::new); 070 map.put(JsonPathExpression.class, JsonPathExpressionReifier::new); 071 map.put(LanguageExpression.class, ExpressionReifier::new); 072 map.put(MethodCallExpression.class, MethodCallExpressionReifier::new); 073 map.put(MvelExpression.class, ExpressionReifier::new); 074 map.put(OgnlExpression.class, ExpressionReifier::new); 075 map.put(RefExpression.class, ExpressionReifier::new); 076 map.put(SimpleExpression.class, SimpleExpressionReifier::new); 077 map.put(SpELExpression.class, ExpressionReifier::new); 078 map.put(TokenizerExpression.class, TokenizerExpressionReifier::new); 079 map.put(XMLTokenizerExpression.class, XMLTokenizerExpressionReifier::new); 080 map.put(XPathExpression.class, XPathExpressionReifier::new); 081 map.put(XQueryExpression.class, XQueryExpressionReifier::new); 082 EXPRESSIONS = map; 083 ReifierStrategy.addReifierClearer(ExpressionReifier::clearReifiers); 084 } 085 086 protected final T definition; 087 088 public ExpressionReifier(CamelContext camelContext, T definition) { 089 super(camelContext); 090 this.definition = definition; 091 } 092 093 public static ExpressionReifier<? extends ExpressionDefinition> reifier(CamelContext camelContext, ExpressionSubElementDefinition definition) { 094 return reifier(camelContext, definition.getExpressionType()); 095 } 096 097 public static ExpressionReifier<? extends ExpressionDefinition> reifier(CamelContext camelContext, ExpressionDefinition definition) { 098 BiFunction<CamelContext, ExpressionDefinition, ExpressionReifier<? extends ExpressionDefinition>> reifier = EXPRESSIONS.get(definition.getClass()); 099 if (reifier != null) { 100 return reifier.apply(camelContext, definition); 101 } 102 throw new IllegalStateException("Unsupported definition: " + definition); 103 } 104 105 public static void clearReifiers() { 106 EXPRESSIONS.clear(); 107 } 108 109 public Expression createExpression() { 110 Expression expression = definition.getExpressionValue(); 111 if (expression == null) { 112 if (definition.getExpressionType() != null) { 113 expression = reifier(camelContext, definition.getExpressionType()).createExpression(); 114 } else { 115 ObjectHelper.notNull(definition.getLanguage(), "language"); 116 Language language = camelContext.resolveLanguage(definition.getLanguage()); 117 if (language == null) { 118 throw new NoSuchLanguageException(definition.getLanguage()); 119 } 120 String exp = parseString(definition.getExpression()); 121 // should be true by default 122 boolean isTrim = parseBoolean(definition.getTrim(), true); 123 // trim if configured to trim 124 if (exp != null && isTrim) { 125 exp = exp.trim(); 126 } 127 // resolve the expression as it may be an external script from 128 // the classpath/file etc 129 exp = ScriptHelper.resolveOptionalExternalScript(camelContext, exp); 130 configureLanguage(language); 131 expression = language.createExpression(exp); 132 configureExpression(expression); 133 } 134 } 135 // inject CamelContext if its aware 136 if (expression instanceof CamelContextAware) { 137 ((CamelContextAware) expression).setCamelContext(camelContext); 138 } 139 expression.init(camelContext); 140 return expression; 141 } 142 143 public Predicate createPredicate() { 144 Predicate predicate = definition.getPredicate(); 145 if (predicate == null) { 146 if (definition.getExpressionType() != null) { 147 predicate = reifier(camelContext, definition.getExpressionType()).createPredicate(); 148 } else if (definition.getExpressionValue() != null) { 149 predicate = new ExpressionToPredicateAdapter(definition.getExpressionValue()); 150 } else if (definition.getExpression() != null) { 151 ObjectHelper.notNull(definition.getLanguage(), "language"); 152 Language language = camelContext.resolveLanguage(definition.getLanguage()); 153 if (language == null) { 154 throw new NoSuchLanguageException(definition.getLanguage()); 155 } 156 String exp = parseString(definition.getExpression()); 157 // should be true by default 158 boolean isTrim = parseBoolean(definition.getTrim(), true); 159 // trim if configured to trim 160 if (exp != null && isTrim) { 161 exp = exp.trim(); 162 } 163 // resolve the expression as it may be an external script from 164 // the classpath/file etc 165 exp = ScriptHelper.resolveOptionalExternalScript(camelContext, exp); 166 configureLanguage(language); 167 predicate = language.createPredicate(exp); 168 configurePredicate(predicate); 169 } 170 } 171 // inject CamelContext if its aware 172 if (predicate instanceof CamelContextAware) { 173 ((CamelContextAware) predicate).setCamelContext(camelContext); 174 } 175 predicate.init(camelContext); 176 return predicate; 177 } 178 179 protected void configureLanguage(Language language) { 180 } 181 182 protected void configurePredicate(Predicate predicate) { 183 // allows to perform additional logic after the properties has been 184 // configured which may be needed 185 // in the various camel components outside camel-core 186 if (predicate instanceof AfterPropertiesConfigured) { 187 ((AfterPropertiesConfigured)predicate).afterPropertiesConfigured(camelContext); 188 } 189 } 190 191 protected void configureExpression(Expression expression) { 192 // allows to perform additional logic after the properties has been 193 // configured which may be needed 194 // in the various camel components outside camel-core 195 if (expression instanceof AfterPropertiesConfigured) { 196 ((AfterPropertiesConfigured)expression).afterPropertiesConfigured(camelContext); 197 } 198 } 199 200 protected void setProperties(Object target, Map<String, Object> properties) { 201 properties.entrySet().removeIf(e -> e.getValue() == null); 202 203 PropertyConfigurer configurer = null; 204 if (target instanceof PropertyConfigurerAware) { 205 configurer = ((PropertyConfigurerAware) target).getPropertyConfigurer(target); 206 } else if (target instanceof PropertyConfigurer) { 207 configurer = (PropertyConfigurer) target; 208 } 209 PropertyBindingSupport.build() 210 .withConfigurer(configurer) 211 .bind(camelContext, target, properties); 212 } 213 214}