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.language; 018 019import java.util.List; 020import java.util.Map; 021import javax.xml.bind.annotation.XmlAccessType; 022import javax.xml.bind.annotation.XmlAccessorType; 023import javax.xml.bind.annotation.XmlAnyAttribute; 024import javax.xml.bind.annotation.XmlAttribute; 025import javax.xml.bind.annotation.XmlID; 026import javax.xml.bind.annotation.XmlRootElement; 027import javax.xml.bind.annotation.XmlTransient; 028import javax.xml.bind.annotation.XmlType; 029import javax.xml.bind.annotation.XmlValue; 030import javax.xml.namespace.QName; 031 032import org.apache.camel.AfterPropertiesConfigured; 033import org.apache.camel.CamelContext; 034import org.apache.camel.CamelContextAware; 035import org.apache.camel.Exchange; 036import org.apache.camel.Expression; 037import org.apache.camel.NoSuchLanguageException; 038import org.apache.camel.Predicate; 039import org.apache.camel.model.OtherAttributesAware; 040import org.apache.camel.spi.Language; 041import org.apache.camel.spi.Metadata; 042import org.apache.camel.spi.RouteContext; 043import org.apache.camel.util.CollectionStringBuffer; 044import org.apache.camel.util.ExpressionToPredicateAdapter; 045import org.apache.camel.util.IntrospectionSupport; 046import org.apache.camel.util.ObjectHelper; 047import org.apache.camel.util.ResourceHelper; 048 049/** 050 * A useful base class for an expression 051 */ 052@Metadata(label = "language", title = "Expression") 053@XmlRootElement 054@XmlType(name = "expression") // must be named expression 055@XmlAccessorType(XmlAccessType.FIELD) 056public class ExpressionDefinition implements Expression, Predicate, OtherAttributesAware { 057 @XmlAttribute 058 @XmlID 059 private String id; 060 @XmlValue @Metadata(required = "true") 061 private String expression; 062 @XmlAttribute @Metadata(defaultValue = "true") 063 private Boolean trim; 064 @XmlTransient 065 private Predicate predicate; 066 @XmlTransient 067 private Expression expressionValue; 068 @XmlTransient 069 private ExpressionDefinition expressionType; 070 // use xs:any to support optional property placeholders 071 @XmlAnyAttribute 072 private Map<QName, Object> otherAttributes; 073 074 public ExpressionDefinition() { 075 } 076 077 public ExpressionDefinition(String expression) { 078 this.expression = expression; 079 } 080 081 public ExpressionDefinition(Predicate predicate) { 082 this.predicate = predicate; 083 } 084 085 public ExpressionDefinition(Expression expression) { 086 this.expressionValue = expression; 087 } 088 089 public static String getLabel(List<ExpressionDefinition> expressions) { 090 CollectionStringBuffer buffer = new CollectionStringBuffer(); 091 for (ExpressionDefinition expression : expressions) { 092 buffer.append(expression.getLabel()); 093 } 094 return buffer.toString(); 095 } 096 097 @Override 098 public String toString() { 099 StringBuilder sb = new StringBuilder(); 100 if (getLanguage() != null) { 101 sb.append(getLanguage()).append("{"); 102 } 103 if (getPredicate() != null) { 104 sb.append(getPredicate().toString()); 105 } 106 if (getExpressionValue() != null) { 107 sb.append(getExpressionValue().toString()); 108 } 109 if (getPredicate() == null && getExpressionValue() == null && getExpression() != null) { 110 sb.append(getExpression()); 111 } 112 if (getLanguage() != null) { 113 sb.append("}"); 114 } 115 return sb.toString(); 116 } 117 118 public Object evaluate(Exchange exchange) { 119 return evaluate(exchange, Object.class); 120 } 121 122 public <T> T evaluate(Exchange exchange, Class<T> type) { 123 if (expressionValue == null) { 124 expressionValue = createExpression(exchange.getContext()); 125 } 126 ObjectHelper.notNull(expressionValue, "expressionValue"); 127 return expressionValue.evaluate(exchange, type); 128 } 129 130 public void assertMatches(String text, Exchange exchange) throws AssertionError { 131 if (!matches(exchange)) { 132 throw new AssertionError(text + getExpression() + " for exchange: " + exchange); 133 } 134 } 135 136 public boolean matches(Exchange exchange) { 137 if (predicate == null) { 138 predicate = createPredicate(exchange.getContext()); 139 } 140 ObjectHelper.notNull(predicate, "predicate"); 141 return predicate.matches(exchange); 142 } 143 144 public String getLanguage() { 145 return ""; 146 } 147 148 public final Predicate createPredicate(RouteContext routeContext) { 149 return createPredicate(routeContext.getCamelContext()); 150 } 151 152 public Predicate createPredicate(CamelContext camelContext) { 153 if (predicate == null) { 154 if (getExpressionType() != null) { 155 predicate = getExpressionType().createPredicate(camelContext); 156 } else if (getExpressionValue() != null) { 157 predicate = new ExpressionToPredicateAdapter(getExpressionValue()); 158 } else if (getExpression() != null) { 159 ObjectHelper.notNull("language", getLanguage()); 160 Language language = camelContext.resolveLanguage(getLanguage()); 161 if (language == null) { 162 throw new NoSuchLanguageException(getLanguage()); 163 } 164 String exp = getExpression(); 165 // should be true by default 166 boolean isTrim = getTrim() == null || getTrim(); 167 // trim if configured to trim 168 if (exp != null && isTrim) { 169 exp = exp.trim(); 170 } 171 // resolve the expression as it may be an external script from the classpath/file etc 172 exp = ResourceHelper.resolveOptionalExternalScript(camelContext, exp); 173 174 predicate = language.createPredicate(exp); 175 configurePredicate(camelContext, predicate); 176 } 177 } 178 // inject CamelContext if its aware 179 if (predicate instanceof CamelContextAware) { 180 ((CamelContextAware) predicate).setCamelContext(camelContext); 181 } 182 return predicate; 183 } 184 185 public final Expression createExpression(RouteContext routeContext) { 186 return createExpression(routeContext.getCamelContext()); 187 } 188 189 public Expression createExpression(CamelContext camelContext) { 190 if (getExpressionValue() == null) { 191 if (getExpressionType() != null) { 192 setExpressionValue(getExpressionType().createExpression(camelContext)); 193 } else if (getExpression() != null) { 194 ObjectHelper.notNull("language", getLanguage()); 195 Language language = camelContext.resolveLanguage(getLanguage()); 196 if (language == null) { 197 throw new NoSuchLanguageException(getLanguage()); 198 } 199 String exp = getExpression(); 200 // should be true by default 201 boolean isTrim = getTrim() == null || getTrim(); 202 // trim if configured to trim 203 if (exp != null && isTrim) { 204 exp = exp.trim(); 205 } 206 // resolve the expression as it may be an external script from the classpath/file etc 207 exp = ResourceHelper.resolveOptionalExternalScript(camelContext, exp); 208 209 setExpressionValue(language.createExpression(exp)); 210 configureExpression(camelContext, getExpressionValue()); 211 } 212 } 213 // inject CamelContext if its aware 214 if (getExpressionValue() instanceof CamelContextAware) { 215 ((CamelContextAware) getExpressionValue()).setCamelContext(camelContext); 216 } 217 return getExpressionValue(); 218 } 219 220 public String getExpression() { 221 return expression; 222 } 223 224 /** 225 * The expression value in your chosen language syntax 226 */ 227 public void setExpression(String expression) { 228 this.expression = expression; 229 } 230 231 public String getId() { 232 return id; 233 } 234 235 /** 236 * Sets the id of this node 237 */ 238 public void setId(String value) { 239 this.id = value; 240 } 241 242 public Predicate getPredicate() { 243 return predicate; 244 } 245 246 public Expression getExpressionValue() { 247 return expressionValue; 248 } 249 250 protected void setExpressionValue(Expression expressionValue) { 251 this.expressionValue = expressionValue; 252 } 253 254 public ExpressionDefinition getExpressionType() { 255 return expressionType; 256 } 257 258 public Boolean getTrim() { 259 return trim; 260 } 261 262 /** 263 * Whether to trim the value to remove leading and trailing whitespaces and line breaks 264 */ 265 public void setTrim(Boolean trim) { 266 this.trim = trim; 267 } 268 269 @Override 270 public Map<QName, Object> getOtherAttributes() { 271 return otherAttributes; 272 } 273 274 @Override 275 public void setOtherAttributes(Map<QName, Object> otherAttributes) { 276 this.otherAttributes = otherAttributes; 277 } 278 279 /** 280 * Returns some descriptive text to describe this node 281 */ 282 public String getLabel() { 283 Predicate predicate = getPredicate(); 284 if (predicate != null) { 285 return predicate.toString(); 286 } 287 Expression expressionValue = getExpressionValue(); 288 if (expressionValue != null) { 289 return expressionValue.toString(); 290 } 291 292 String exp = getExpression(); 293 return exp != null ? exp : ""; 294 } 295 296 /** 297 * Allows derived classes to set a lazily created expressionType instance 298 * such as if using the {@link org.apache.camel.builder.ExpressionClause} 299 */ 300 protected void setExpressionType(ExpressionDefinition expressionType) { 301 this.expressionType = expressionType; 302 } 303 304 protected void configurePredicate(CamelContext camelContext, Predicate predicate) { 305 // allows to perform additional logic after the properties has been configured which may be needed 306 // in the various camel components outside camel-core 307 if (predicate instanceof AfterPropertiesConfigured) { 308 ((AfterPropertiesConfigured) predicate).afterPropertiesConfigured(camelContext); 309 } 310 } 311 312 protected void configureExpression(CamelContext camelContext, Expression expression) { 313 // allows to perform additional logic after the properties has been configured which may be needed 314 // in the various camel components outside camel-core 315 if (expression instanceof AfterPropertiesConfigured) { 316 ((AfterPropertiesConfigured) expression).afterPropertiesConfigured(camelContext); 317 } 318 } 319 320 /** 321 * Sets a named property on the object instance using introspection 322 */ 323 protected void setProperty(Object bean, String name, Object value) { 324 try { 325 IntrospectionSupport.setProperty(bean, name, value); 326 } catch (Exception e) { 327 throw new IllegalArgumentException("Failed to set property " + name + " on " + bean 328 + ". Reason: " + e, e); 329 } 330 } 331}