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 return expression; 140 } 141 142 public Predicate createPredicate() { 143 Predicate predicate = definition.getPredicate(); 144 if (predicate == null) { 145 if (definition.getExpressionType() != null) { 146 predicate = reifier(camelContext, definition.getExpressionType()).createPredicate(); 147 } else if (definition.getExpressionValue() != null) { 148 predicate = new ExpressionToPredicateAdapter(definition.getExpressionValue()); 149 } else if (definition.getExpression() != null) { 150 ObjectHelper.notNull(definition.getLanguage(), "language"); 151 Language language = camelContext.resolveLanguage(definition.getLanguage()); 152 if (language == null) { 153 throw new NoSuchLanguageException(definition.getLanguage()); 154 } 155 String exp = parseString(definition.getExpression()); 156 // should be true by default 157 boolean isTrim = parseBoolean(definition.getTrim(), true); 158 // trim if configured to trim 159 if (exp != null && isTrim) { 160 exp = exp.trim(); 161 } 162 // resolve the expression as it may be an external script from 163 // the classpath/file etc 164 exp = ScriptHelper.resolveOptionalExternalScript(camelContext, exp); 165 configureLanguage(language); 166 predicate = language.createPredicate(exp); 167 configurePredicate(predicate); 168 } 169 } 170 // inject CamelContext if its aware 171 if (predicate instanceof CamelContextAware) { 172 ((CamelContextAware) predicate).setCamelContext(camelContext); 173 } 174 return predicate; 175 } 176 177 protected void configureLanguage(Language language) { 178 } 179 180 protected void configurePredicate(Predicate predicate) { 181 // allows to perform additional logic after the properties has been 182 // configured which may be needed 183 // in the various camel components outside camel-core 184 if (predicate instanceof AfterPropertiesConfigured) { 185 ((AfterPropertiesConfigured)predicate).afterPropertiesConfigured(camelContext); 186 } 187 } 188 189 protected void configureExpression(Expression expression) { 190 // allows to perform additional logic after the properties has been 191 // configured which may be needed 192 // in the various camel components outside camel-core 193 if (expression instanceof AfterPropertiesConfigured) { 194 ((AfterPropertiesConfigured)expression).afterPropertiesConfigured(camelContext); 195 } 196 } 197 198 protected void setProperties(Object target, Map<String, Object> properties) { 199 properties.entrySet().removeIf(e -> e.getValue() == null); 200 201 PropertyConfigurer configurer = null; 202 if (target instanceof PropertyConfigurerAware) { 203 configurer = ((PropertyConfigurerAware) target).getPropertyConfigurer(target); 204 } else if (target instanceof PropertyConfigurer) { 205 configurer = (PropertyConfigurer) target; 206 } 207 PropertyBindingSupport.build() 208 .withConfigurer(configurer) 209 .bind(camelContext, target, properties); 210 } 211 212}