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 }