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