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 */ 017 package org.apache.camel.language.simple.ast; 018 019 import org.apache.camel.Expression; 020 import org.apache.camel.builder.ExpressionBuilder; 021 import org.apache.camel.language.simple.types.SimpleParserException; 022 import org.apache.camel.language.simple.types.SimpleToken; 023 import org.apache.camel.util.ObjectHelper; 024 import org.apache.camel.util.OgnlHelper; 025 import org.apache.camel.util.StringHelper; 026 027 /** 028 * Represents one of built-in functions of the 029 * <a href="http://camel.apache.org/simple.html">simple language</a> 030 */ 031 public class SimpleFunctionExpression extends LiteralExpression { 032 033 public SimpleFunctionExpression(SimpleToken token) { 034 super(token); 035 } 036 037 @Override 038 public Expression createExpression(String expression) { 039 String function = text.toString(); 040 return createSimpleExpression(function, true); 041 } 042 043 /** 044 * Creates a Camel {@link Expression} based on this model. 045 * 046 * @param expression the input string 047 * @param strict whether to throw exception if the expression was not a function, 048 * otherwise <tt>null</tt> is returned 049 * @return the created {@link Expression} 050 * @throws org.apache.camel.language.simple.types.SimpleParserException 051 * should be thrown if error parsing the model 052 */ 053 public Expression createExpression(String expression, boolean strict) { 054 String function = text.toString(); 055 return createSimpleExpression(function, strict); 056 } 057 058 private Expression createSimpleExpression(String function, boolean strict) { 059 // return the function directly if we can create function without analyzing the prefix 060 Expression answer = createSimpleExpressionDirectly(function); 061 if (answer != null) { 062 return answer; 063 } 064 065 // body and headers first 066 answer = createSimpleExpressionBodyOrHeader(function, strict); 067 if (answer != null) { 068 return answer; 069 } 070 071 // camelContext OGNL 072 String remainder = ifStartsWithReturnRemainder("camelContext", function); 073 if (remainder != null) { 074 boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder); 075 if (invalid) { 076 throw new SimpleParserException("Valid syntax: ${camelContext.OGNL} was: " + function, token.getIndex()); 077 } 078 return ExpressionBuilder.camelContextOgnlExpression(remainder); 079 } 080 081 // Exception OGNL 082 remainder = ifStartsWithReturnRemainder("exception", function); 083 if (remainder != null) { 084 boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder); 085 if (invalid) { 086 throw new SimpleParserException("Valid syntax: ${exception.OGNL} was: " + function, token.getIndex()); 087 } 088 return ExpressionBuilder.exchangeExceptionOgnlExpression(remainder); 089 } 090 091 // property 092 remainder = ifStartsWithReturnRemainder("property", function); 093 if (remainder != null) { 094 // remove leading character (dot or ?) 095 if (remainder.startsWith(".") || remainder.startsWith("?")) { 096 remainder = remainder.substring(1); 097 } 098 // remove starting and ending brackets 099 if (remainder.startsWith("[") && remainder.endsWith("]")) { 100 remainder = remainder.substring(1, remainder.length() - 1); 101 } 102 103 // validate syntax 104 boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder); 105 if (invalid) { 106 throw new SimpleParserException("Valid syntax: ${property.OGNL} was: " + function, token.getIndex()); 107 } 108 109 if (OgnlHelper.isValidOgnlExpression(remainder)) { 110 // ognl based property 111 return ExpressionBuilder.propertyOgnlExpression(remainder); 112 } else { 113 // regular property 114 return ExpressionBuilder.propertyExpression(remainder); 115 } 116 } 117 118 // system property 119 remainder = ifStartsWithReturnRemainder("sys.", function); 120 if (remainder != null) { 121 return ExpressionBuilder.systemPropertyExpression(remainder); 122 } 123 remainder = ifStartsWithReturnRemainder("sysenv.", function); 124 if (remainder != null) { 125 return ExpressionBuilder.systemEnvironmentExpression(remainder); 126 } 127 128 // file: prefix 129 remainder = ifStartsWithReturnRemainder("file:", function); 130 if (remainder != null) { 131 Expression fileExpression = createSimpleFileExpression(remainder); 132 if (function != null) { 133 return fileExpression; 134 } 135 } 136 137 // date: prefix 138 remainder = ifStartsWithReturnRemainder("date:", function); 139 if (remainder != null) { 140 String[] parts = remainder.split(":"); 141 if (parts.length < 2) { 142 throw new SimpleParserException("Valid syntax: ${date:command:pattern} was: " + function, token.getIndex()); 143 } 144 String command = ObjectHelper.before(remainder, ":"); 145 String pattern = ObjectHelper.after(remainder, ":"); 146 return ExpressionBuilder.dateExpression(command, pattern); 147 } 148 149 // bean: prefix 150 remainder = ifStartsWithReturnRemainder("bean:", function); 151 if (remainder != null) { 152 return ExpressionBuilder.beanExpression(remainder); 153 } 154 155 // properties: prefix 156 remainder = ifStartsWithReturnRemainder("properties:", function); 157 if (remainder != null) { 158 String[] parts = remainder.split(":"); 159 if (parts.length > 2) { 160 throw new SimpleParserException("Valid syntax: ${properties:[locations]:key} was: " + function, token.getIndex()); 161 } 162 163 String locations = null; 164 String key = remainder; 165 if (parts.length == 2) { 166 locations = ObjectHelper.before(remainder, ":"); 167 key = ObjectHelper.after(remainder, ":"); 168 } 169 return ExpressionBuilder.propertiesComponentExpression(key, locations); 170 } 171 172 // ref: prefix 173 remainder = ifStartsWithReturnRemainder("ref:", function); 174 if (remainder != null) { 175 return ExpressionBuilder.refExpression(remainder); 176 } 177 178 // const: prefix 179 remainder = ifStartsWithReturnRemainder("type:", function); 180 if (remainder != null) { 181 Expression exp = ExpressionBuilder.typeExpression(remainder); 182 // we want to cache this expression so we wont re-evaluate it as the type/constant wont change 183 return ExpressionBuilder.cacheExpression(exp); 184 } 185 186 if (strict) { 187 throw new SimpleParserException("Unknown function: " + function, token.getIndex()); 188 } else { 189 return null; 190 } 191 } 192 193 private Expression createSimpleExpressionBodyOrHeader(String function, boolean strict) { 194 // bodyAs 195 String remainder = ifStartsWithReturnRemainder("bodyAs", function); 196 if (remainder != null) { 197 String type = ObjectHelper.between(remainder, "(", ")"); 198 if (type == null) { 199 throw new SimpleParserException("Valid syntax: ${bodyAs(type)} was: " + function, token.getIndex()); 200 } 201 type = StringHelper.removeQuotes(type); 202 return ExpressionBuilder.bodyExpression(type); 203 } 204 // mandatoryBodyAs 205 remainder = ifStartsWithReturnRemainder("mandatoryBodyAs", function); 206 if (remainder != null) { 207 String type = ObjectHelper.between(remainder, "(", ")"); 208 if (type == null) { 209 throw new SimpleParserException("Valid syntax: ${mandatoryBodyAs(type)} was: " + function, token.getIndex()); 210 } 211 type = StringHelper.removeQuotes(type); 212 return ExpressionBuilder.mandatoryBodyExpression(type); 213 } 214 215 // body OGNL 216 remainder = ifStartsWithReturnRemainder("body", function); 217 if (remainder == null) { 218 remainder = ifStartsWithReturnRemainder("in.body", function); 219 } 220 if (remainder != null) { 221 boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder); 222 if (invalid) { 223 throw new SimpleParserException("Valid syntax: ${body.OGNL} was: " + function, token.getIndex()); 224 } 225 return ExpressionBuilder.bodyOgnlExpression(remainder); 226 } 227 228 // headerAs 229 remainder = ifStartsWithReturnRemainder("headerAs", function); 230 if (remainder != null) { 231 String keyAndType = ObjectHelper.between(remainder, "(", ")"); 232 if (keyAndType == null) { 233 throw new SimpleParserException("Valid syntax: ${headerAs(key, type)} was: " + function, token.getIndex()); 234 } 235 236 String key = ObjectHelper.before(keyAndType, ","); 237 String type = ObjectHelper.after(keyAndType, ","); 238 if (ObjectHelper.isEmpty(key) || ObjectHelper.isEmpty(type)) { 239 throw new SimpleParserException("Valid syntax: ${headerAs(key, type)} was: " + function, token.getIndex()); 240 } 241 key = StringHelper.removeQuotes(key); 242 type = StringHelper.removeQuotes(type); 243 return ExpressionBuilder.headerExpression(key, type); 244 } 245 246 // headers function 247 if ("in.headers".equals(function) || "headers".equals(function)) { 248 return ExpressionBuilder.headersExpression(); 249 } 250 251 // in header function 252 remainder = ifStartsWithReturnRemainder("in.headers", function); 253 if (remainder == null) { 254 remainder = ifStartsWithReturnRemainder("in.header", function); 255 } 256 if (remainder == null) { 257 remainder = ifStartsWithReturnRemainder("headers", function); 258 } 259 if (remainder == null) { 260 remainder = ifStartsWithReturnRemainder("header", function); 261 } 262 if (remainder != null) { 263 // remove leading character (dot or ?) 264 if (remainder.startsWith(".") || remainder.startsWith("?")) { 265 remainder = remainder.substring(1); 266 } 267 // remove starting and ending brackets 268 if (remainder.startsWith("[") && remainder.endsWith("]")) { 269 remainder = remainder.substring(1, remainder.length() - 1); 270 } 271 272 // validate syntax 273 boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder); 274 if (invalid) { 275 throw new SimpleParserException("Valid syntax: ${header.name[key]} was: " + function, token.getIndex()); 276 } 277 278 if (OgnlHelper.isValidOgnlExpression(remainder)) { 279 // ognl based header 280 return ExpressionBuilder.headersOgnlExpression(remainder); 281 } else { 282 // regular header 283 return ExpressionBuilder.headerExpression(remainder); 284 } 285 } 286 287 // out header function 288 remainder = ifStartsWithReturnRemainder("out.header.", function); 289 if (remainder == null) { 290 remainder = ifStartsWithReturnRemainder("out.headers.", function); 291 } 292 if (remainder != null) { 293 return ExpressionBuilder.outHeaderExpression(remainder); 294 } 295 296 return null; 297 } 298 299 private Expression createSimpleExpressionDirectly(String expression) { 300 if (ObjectHelper.isEqualToAny(expression, "body", "in.body")) { 301 return ExpressionBuilder.bodyExpression(); 302 } else if (ObjectHelper.equal(expression, "out.body")) { 303 return ExpressionBuilder.outBodyExpression(); 304 } else if (ObjectHelper.equal(expression, "id")) { 305 return ExpressionBuilder.messageIdExpression(); 306 } else if (ObjectHelper.equal(expression, "exchangeId")) { 307 return ExpressionBuilder.exchangeIdExpression(); 308 } else if (ObjectHelper.equal(expression, "exception")) { 309 return ExpressionBuilder.exchangeExceptionExpression(); 310 } else if (ObjectHelper.equal(expression, "exception.message")) { 311 return ExpressionBuilder.exchangeExceptionMessageExpression(); 312 } else if (ObjectHelper.equal(expression, "exception.stacktrace")) { 313 return ExpressionBuilder.exchangeExceptionStackTraceExpression(); 314 } else if (ObjectHelper.equal(expression, "threadName")) { 315 return ExpressionBuilder.threadNameExpression(); 316 } else if (ObjectHelper.equal(expression, "camelId")) { 317 return ExpressionBuilder.camelContextNameExpression(); 318 } else if (ObjectHelper.equal(expression, "routeId")) { 319 return ExpressionBuilder.routeIdExpression(); 320 } else if (ObjectHelper.equal(expression, "null")) { 321 return ExpressionBuilder.nullExpression(); 322 } 323 324 return null; 325 } 326 327 private Expression createSimpleFileExpression(String remainder) { 328 if (ObjectHelper.equal(remainder, "name")) { 329 return ExpressionBuilder.fileNameExpression(); 330 } else if (ObjectHelper.equal(remainder, "name.noext")) { 331 return ExpressionBuilder.fileNameNoExtensionExpression(); 332 } else if (ObjectHelper.equal(remainder, "name.ext")) { 333 return ExpressionBuilder.fileExtensionExpression(); 334 } else if (ObjectHelper.equal(remainder, "onlyname")) { 335 return ExpressionBuilder.fileOnlyNameExpression(); 336 } else if (ObjectHelper.equal(remainder, "onlyname.noext")) { 337 return ExpressionBuilder.fileOnlyNameNoExtensionExpression(); 338 } else if (ObjectHelper.equal(remainder, "ext")) { 339 return ExpressionBuilder.fileExtensionExpression(); 340 } else if (ObjectHelper.equal(remainder, "parent")) { 341 return ExpressionBuilder.fileParentExpression(); 342 } else if (ObjectHelper.equal(remainder, "path")) { 343 return ExpressionBuilder.filePathExpression(); 344 } else if (ObjectHelper.equal(remainder, "absolute")) { 345 return ExpressionBuilder.fileAbsoluteExpression(); 346 } else if (ObjectHelper.equal(remainder, "absolute.path")) { 347 return ExpressionBuilder.fileAbsolutePathExpression(); 348 } else if (ObjectHelper.equal(remainder, "length") || ObjectHelper.equal(remainder, "size")) { 349 return ExpressionBuilder.fileSizeExpression(); 350 } else if (ObjectHelper.equal(remainder, "modified")) { 351 return ExpressionBuilder.fileLastModifiedExpression(); 352 } 353 throw new SimpleParserException("Unknown file language syntax: " + remainder, token.getIndex()); 354 } 355 356 private String ifStartsWithReturnRemainder(String prefix, String text) { 357 if (text.startsWith(prefix)) { 358 String remainder = text.substring(prefix.length()); 359 if (remainder.length() > 0) { 360 return remainder; 361 } 362 } 363 return null; 364 } 365 366 }