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 // bodyAs 066 String remainder = ifStartsWithReturnRemainder("bodyAs", function); 067 if (remainder != null) { 068 String type = ObjectHelper.between(remainder, "(", ")"); 069 if (type == null) { 070 throw new SimpleParserException("Valid syntax: ${bodyAs(type)} was: " + function, token.getIndex()); 071 } 072 type = StringHelper.removeQuotes(type); 073 return ExpressionBuilder.bodyExpression(type); 074 } 075 // mandatoryBodyAs 076 remainder = ifStartsWithReturnRemainder("mandatoryBodyAs", function); 077 if (remainder != null) { 078 String type = ObjectHelper.between(remainder, "(", ")"); 079 if (type == null) { 080 throw new SimpleParserException("Valid syntax: ${mandatoryBodyAs(type)} was: " + function, token.getIndex()); 081 } 082 type = StringHelper.removeQuotes(type); 083 return ExpressionBuilder.mandatoryBodyExpression(type); 084 } 085 086 // body OGNL 087 remainder = ifStartsWithReturnRemainder("body", function); 088 if (remainder == null) { 089 remainder = ifStartsWithReturnRemainder("in.body", function); 090 } 091 if (remainder != null) { 092 boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder); 093 if (invalid) { 094 throw new SimpleParserException("Valid syntax: ${body.OGNL} was: " + function, token.getIndex()); 095 } 096 return ExpressionBuilder.bodyOgnlExpression(remainder); 097 } 098 099 // Exception OGNL 100 remainder = ifStartsWithReturnRemainder("exception", function); 101 if (remainder != null) { 102 boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder); 103 if (invalid) { 104 throw new SimpleParserException("Valid syntax: ${exception.OGNL} was: " + function, token.getIndex()); 105 } 106 return ExpressionBuilder.exchangeExceptionOgnlExpression(remainder); 107 } 108 109 // headerAs 110 remainder = ifStartsWithReturnRemainder("headerAs", function); 111 if (remainder != null) { 112 String keyAndType = ObjectHelper.between(remainder, "(", ")"); 113 if (keyAndType == null) { 114 throw new SimpleParserException("Valid syntax: ${headerAs(key, type)} was: " + function, token.getIndex()); 115 } 116 117 String key = ObjectHelper.before(keyAndType, ","); 118 String type = ObjectHelper.after(keyAndType, ","); 119 if (ObjectHelper.isEmpty(key) || ObjectHelper.isEmpty(type)) { 120 throw new SimpleParserException("Valid syntax: ${headerAs(key, type)} was: " + function, token.getIndex()); 121 } 122 key = StringHelper.removeQuotes(key); 123 type = StringHelper.removeQuotes(type); 124 return ExpressionBuilder.headerExpression(key, type); 125 } 126 127 // headers function 128 if ("in.headers".equals(function) || "headers".equals(function)) { 129 return ExpressionBuilder.headersExpression(); 130 } 131 132 // in header function 133 remainder = ifStartsWithReturnRemainder("in.headers", function); 134 if (remainder == null) { 135 remainder = ifStartsWithReturnRemainder("in.header", function); 136 } 137 if (remainder == null) { 138 remainder = ifStartsWithReturnRemainder("headers", function); 139 } 140 if (remainder == null) { 141 remainder = ifStartsWithReturnRemainder("header", function); 142 } 143 if (remainder != null) { 144 // remove leading character (dot or ?) 145 if (remainder.startsWith(".") || remainder.startsWith("?")) { 146 remainder = remainder.substring(1); 147 } 148 // remove starting and ending brackets 149 if (remainder.startsWith("[") && remainder.endsWith("]")) { 150 remainder = remainder.substring(1, remainder.length() - 1); 151 } 152 153 // validate syntax 154 boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder); 155 if (invalid) { 156 throw new SimpleParserException("Valid syntax: ${header.name[key]} was: " + function, token.getIndex()); 157 } 158 159 if (OgnlHelper.isValidOgnlExpression(remainder)) { 160 // ognl based header 161 return ExpressionBuilder.headersOgnlExpression(remainder); 162 } else { 163 // regular header 164 return ExpressionBuilder.headerExpression(remainder); 165 } 166 } 167 168 // out header function 169 remainder = ifStartsWithReturnRemainder("out.header.", function); 170 if (remainder == null) { 171 remainder = ifStartsWithReturnRemainder("out.headers.", function); 172 } 173 if (remainder != null) { 174 return ExpressionBuilder.outHeaderExpression(remainder); 175 } 176 177 // property 178 remainder = ifStartsWithReturnRemainder("property", function); 179 if (remainder != null) { 180 // remove leading character (dot or ?) 181 if (remainder.startsWith(".") || remainder.startsWith("?")) { 182 remainder = remainder.substring(1); 183 } 184 // remove starting and ending brackets 185 if (remainder.startsWith("[") && remainder.endsWith("]")) { 186 remainder = remainder.substring(1, remainder.length() - 1); 187 } 188 189 // validate syntax 190 boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder); 191 if (invalid) { 192 throw new SimpleParserException("Valid syntax: ${property.OGNL} was: " + function, token.getIndex()); 193 } 194 195 if (OgnlHelper.isValidOgnlExpression(remainder)) { 196 // ognl based property 197 return ExpressionBuilder.propertyOgnlExpression(remainder); 198 } else { 199 // regular property 200 return ExpressionBuilder.propertyExpression(remainder); 201 } 202 } 203 204 // system property 205 remainder = ifStartsWithReturnRemainder("sys.", function); 206 if (remainder != null) { 207 return ExpressionBuilder.systemPropertyExpression(remainder); 208 } 209 210 // system property 211 remainder = ifStartsWithReturnRemainder("sysenv.", function); 212 if (remainder != null) { 213 return ExpressionBuilder.systemEnvironmentExpression(remainder); 214 } 215 216 // file: prefix 217 remainder = ifStartsWithReturnRemainder("file:", function); 218 if (remainder != null) { 219 Expression fileExpression = createSimpleFileExpression(remainder); 220 if (function != null) { 221 return fileExpression; 222 } 223 } 224 225 // date: prefix 226 remainder = ifStartsWithReturnRemainder("date:", function); 227 if (remainder != null) { 228 String[] parts = remainder.split(":"); 229 if (parts.length < 2) { 230 throw new SimpleParserException("Valid syntax: ${date:command:pattern} was: " + function, token.getIndex()); 231 } 232 String command = ObjectHelper.before(remainder, ":"); 233 String pattern = ObjectHelper.after(remainder, ":"); 234 return ExpressionBuilder.dateExpression(command, pattern); 235 } 236 237 // bean: prefix 238 remainder = ifStartsWithReturnRemainder("bean:", function); 239 if (remainder != null) { 240 return ExpressionBuilder.beanExpression(remainder); 241 } 242 243 // properties: prefix 244 remainder = ifStartsWithReturnRemainder("properties:", function); 245 if (remainder != null) { 246 String[] parts = remainder.split(":"); 247 if (parts.length > 2) { 248 throw new SimpleParserException("Valid syntax: ${properties:[locations]:key} was: " + function, token.getIndex()); 249 } 250 251 String locations = null; 252 String key = remainder; 253 if (parts.length == 2) { 254 locations = ObjectHelper.before(remainder, ":"); 255 key = ObjectHelper.after(remainder, ":"); 256 } 257 return ExpressionBuilder.propertiesComponentExpression(key, locations); 258 } 259 260 // ref: prefix 261 remainder = ifStartsWithReturnRemainder("ref:", function); 262 if (remainder != null) { 263 return ExpressionBuilder.refExpression(remainder); 264 } 265 266 if (strict) { 267 throw new SimpleParserException("Unknown function: " + function, token.getIndex()); 268 } else { 269 return null; 270 } 271 } 272 273 private Expression createSimpleExpressionDirectly(String expression) { 274 if (ObjectHelper.isEqualToAny(expression, "body", "in.body")) { 275 return ExpressionBuilder.bodyExpression(); 276 } else if (ObjectHelper.equal(expression, "out.body")) { 277 return ExpressionBuilder.outBodyExpression(); 278 } else if (ObjectHelper.equal(expression, "id")) { 279 return ExpressionBuilder.messageIdExpression(); 280 } else if (ObjectHelper.equal(expression, "exchangeId")) { 281 return ExpressionBuilder.exchangeIdExpression(); 282 } else if (ObjectHelper.equal(expression, "exception")) { 283 return ExpressionBuilder.exchangeExceptionExpression(); 284 } else if (ObjectHelper.equal(expression, "exception.message")) { 285 return ExpressionBuilder.exchangeExceptionMessageExpression(); 286 } else if (ObjectHelper.equal(expression, "exception.stacktrace")) { 287 return ExpressionBuilder.exchangeExceptionStackTraceExpression(); 288 } else if (ObjectHelper.equal(expression, "threadName")) { 289 return ExpressionBuilder.threadNameExpression(); 290 } else if (ObjectHelper.equal(expression, "camelId")) { 291 return ExpressionBuilder.camelContextNameExpression(); 292 } 293 294 return null; 295 } 296 297 private Expression createSimpleFileExpression(String remainder) { 298 if (ObjectHelper.equal(remainder, "name")) { 299 return ExpressionBuilder.fileNameExpression(); 300 } else if (ObjectHelper.equal(remainder, "name.noext")) { 301 return ExpressionBuilder.fileNameNoExtensionExpression(); 302 } else if (ObjectHelper.equal(remainder, "name.ext")) { 303 return ExpressionBuilder.fileExtensionExpression(); 304 } else if (ObjectHelper.equal(remainder, "onlyname")) { 305 return ExpressionBuilder.fileOnlyNameExpression(); 306 } else if (ObjectHelper.equal(remainder, "onlyname.noext")) { 307 return ExpressionBuilder.fileOnlyNameNoExtensionExpression(); 308 } else if (ObjectHelper.equal(remainder, "ext")) { 309 return ExpressionBuilder.fileExtensionExpression(); 310 } else if (ObjectHelper.equal(remainder, "parent")) { 311 return ExpressionBuilder.fileParentExpression(); 312 } else if (ObjectHelper.equal(remainder, "path")) { 313 return ExpressionBuilder.filePathExpression(); 314 } else if (ObjectHelper.equal(remainder, "absolute")) { 315 return ExpressionBuilder.fileAbsoluteExpression(); 316 } else if (ObjectHelper.equal(remainder, "absolute.path")) { 317 return ExpressionBuilder.fileAbsolutePathExpression(); 318 } else if (ObjectHelper.equal(remainder, "length") || ObjectHelper.equal(remainder, "size")) { 319 return ExpressionBuilder.fileSizeExpression(); 320 } else if (ObjectHelper.equal(remainder, "modified")) { 321 return ExpressionBuilder.fileLastModifiedExpression(); 322 } 323 throw new SimpleParserException("Unknown file language syntax: " + remainder, token.getIndex()); 324 } 325 326 private String ifStartsWithReturnRemainder(String prefix, String text) { 327 if (text.startsWith(prefix)) { 328 String remainder = text.substring(prefix.length()); 329 if (remainder.length() > 0) { 330 return remainder; 331 } 332 } 333 return null; 334 } 335 336 }