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.builder;
018    
019    import java.io.PrintWriter;
020    import java.io.StringWriter;
021    import java.text.SimpleDateFormat;
022    import java.util.Collection;
023    import java.util.Collections;
024    import java.util.Comparator;
025    import java.util.Date;
026    import java.util.Iterator;
027    import java.util.List;
028    import java.util.Scanner;
029    import java.util.regex.Pattern;
030    
031    import org.apache.camel.Component;
032    import org.apache.camel.Endpoint;
033    import org.apache.camel.Exchange;
034    import org.apache.camel.Expression;
035    import org.apache.camel.InvalidPayloadException;
036    import org.apache.camel.Message;
037    import org.apache.camel.NoSuchEndpointException;
038    import org.apache.camel.Producer;
039    import org.apache.camel.component.bean.BeanInvocation;
040    import org.apache.camel.component.properties.PropertiesComponent;
041    import org.apache.camel.language.bean.BeanLanguage;
042    import org.apache.camel.model.language.MethodCallExpression;
043    import org.apache.camel.spi.Language;
044    import org.apache.camel.support.ExpressionAdapter;
045    import org.apache.camel.support.TokenPairExpressionIterator;
046    import org.apache.camel.support.TokenXMLPairExpressionIterator;
047    import org.apache.camel.util.ExchangeHelper;
048    import org.apache.camel.util.FileUtil;
049    import org.apache.camel.util.GroupIterator;
050    import org.apache.camel.util.IOHelper;
051    import org.apache.camel.util.ObjectHelper;
052    import org.apache.camel.util.OgnlHelper;
053    
054    /**
055     * A helper class for working with <a href="http://camel.apache.org/expression.html">expressions</a>.
056     *
057     * @version 
058     */
059    public final class ExpressionBuilder {
060    
061        /**
062         * Utility classes should not have a public constructor.
063         */
064        private ExpressionBuilder() {
065        }
066        
067        /**
068         * Returns an expression for the inbound message attachments
069         *
070         * @return an expression object which will return the inbound message attachments
071         */
072        public static Expression attachmentsExpression() {
073            return new ExpressionAdapter() {
074                public Object evaluate(Exchange exchange) {
075                    return exchange.getIn().getAttachments();
076                }
077    
078                @Override
079                public String toString() {
080                    return "attachments";
081                }
082            };
083        }
084    
085        /**
086         * Returns an expression for the inbound message attachments
087         *
088         * @return an expression object which will return the inbound message attachments
089         */
090        public static Expression attachmentValuesExpression() {
091            return new ExpressionAdapter() {
092                public Object evaluate(Exchange exchange) {
093                    return exchange.getIn().getAttachments().values();
094                }
095    
096                @Override
097                public String toString() {
098                    return "attachments";
099                }
100            };
101        }
102    
103        /**
104         * Returns an expression for the header value with the given name
105         * <p/>
106         * Will fallback and look in properties if not found in headers.
107         *
108         * @param headerName the name of the header the expression will return
109         * @return an expression object which will return the header value
110         */
111        public static Expression headerExpression(final String headerName) {
112            return new ExpressionAdapter() {
113                public Object evaluate(Exchange exchange) {
114                    Object header = exchange.getIn().getHeader(headerName);
115                    if (header == null) {
116                        // fall back on a property
117                        header = exchange.getProperty(headerName);
118                    }
119                    return header;
120                }
121    
122                @Override
123                public String toString() {
124                    return "header(" + headerName + ")";
125                }
126            };
127        }
128    
129        /**
130         * Returns an expression for the header value with the given name converted to the given type
131         * <p/>
132         * Will fallback and look in properties if not found in headers.
133         *
134         * @param headerName the name of the header the expression will return
135         * @param type the type to convert to
136         * @return an expression object which will return the header value
137         */
138        public static <T> Expression headerExpression(final String headerName, final Class<T> type) {
139            return new ExpressionAdapter() {
140                public Object evaluate(Exchange exchange) {
141                    Object header = exchange.getIn().getHeader(headerName, type);
142                    if (header == null) {
143                        // fall back on a property
144                        header = exchange.getProperty(headerName, type);
145                    }
146                    return header;
147                }
148    
149                @Override
150                public String toString() {
151                    return "headerAs(" + headerName + ", " + type + ")";
152                }
153            };
154        }
155    
156        /**
157         * Returns an expression for the header value with the given name converted to the given type
158         * <p/>
159         * Will fallback and look in properties if not found in headers.
160         *
161         * @param headerName the name of the header the expression will return
162         * @param name the type to convert to as a FQN class name
163         * @return an expression object which will return the header value
164         */
165        public static Expression headerExpression(final String headerName, final String name) {
166            return new ExpressionAdapter() {
167                public Object evaluate(Exchange exchange) {
168                    Class<?> type;
169                    try {
170                        type = exchange.getContext().getClassResolver().resolveMandatoryClass(name);
171                    } catch (ClassNotFoundException e) {
172                        throw ObjectHelper.wrapCamelExecutionException(exchange, e);
173                    }
174    
175                    Object header = exchange.getIn().getHeader(headerName, type);
176                    if (header == null) {
177                        // fall back on a property
178                        header = exchange.getProperty(headerName, type);
179                    }
180                    return header;
181                }
182    
183                @Override
184                public String toString() {
185                    return "headerAs(" + headerName + ", " + name + ")";
186                }
187            };
188        }
189    
190        /**
191         * Returns the expression for the exchanges inbound message header invoking methods defined
192         * in a simple OGNL notation
193         *
194         * @param ognl  methods to invoke on the header in a simple OGNL syntax
195         */
196        public static Expression headersOgnlExpression(final String ognl) {
197            return new KeyedOgnlExpressionAdapter(ognl, "headerOgnl(" + ognl + ")",
198                new KeyedOgnlExpressionAdapter.KeyedEntityRetrievalStrategy() {
199                    public Object getKeyedEntity(Exchange exchange, String key) {
200                        return exchange.getIn().getHeader(key);
201                    }
202                });
203        }
204    
205        /**
206         * Returns an expression for the inbound message headers
207         *
208         * @return an expression object which will return the inbound headers
209         */
210        public static Expression headersExpression() {
211            return new ExpressionAdapter() {
212                public Object evaluate(Exchange exchange) {
213                    return exchange.getIn().getHeaders();
214                }
215    
216                @Override
217                public String toString() {
218                    return "headers";
219                }
220            };
221        }
222    
223        /**
224         * Returns an expression for the out header value with the given name
225         * <p/>
226         * Will fallback and look in properties if not found in headers.
227         *
228         * @param headerName the name of the header the expression will return
229         * @return an expression object which will return the header value
230         */
231        public static Expression outHeaderExpression(final String headerName) {
232            return new ExpressionAdapter() {
233                public Object evaluate(Exchange exchange) {
234                    if (!exchange.hasOut()) {
235                        return null;
236                    }
237    
238                    Message out = exchange.getOut();
239                    Object header = out.getHeader(headerName);
240                    if (header == null) {
241                        // let's try the exchange header
242                        header = exchange.getProperty(headerName);
243                    }
244                    return header;
245                }
246    
247                @Override
248                public String toString() {
249                    return "outHeader(" + headerName + ")";
250                }
251            };
252        }
253    
254        /**
255         * Returns an expression for the outbound message headers
256         *
257         * @return an expression object which will return the headers, will be <tt>null</tt> if the
258         * exchange is not out capable.
259         */
260        public static Expression outHeadersExpression() {
261            return new ExpressionAdapter() {
262                public Object evaluate(Exchange exchange) {
263                    // only get out headers if the MEP is out capable
264                    if (ExchangeHelper.isOutCapable(exchange)) {
265                        return exchange.getOut().getHeaders();
266                    } else {
267                        return null;
268                    }
269                }
270    
271                @Override
272                public String toString() {
273                    return "outHeaders";
274                }
275            };
276        }
277    
278        /**
279         * Returns an expression for the exchange pattern
280         *
281         * @see org.apache.camel.Exchange#getPattern()
282         * @return an expression object which will return the exchange pattern
283         */
284        public static Expression exchangePatternExpression() {
285            return new ExpressionAdapter() {
286                public Object evaluate(Exchange exchange) {
287                    return exchange.getPattern();
288                }
289    
290                @Override
291                public String toString() {
292                    return "exchangePattern";
293                }
294            };
295        }   
296        
297        /**
298         * Returns an expression for an exception set on the exchange
299         *
300         * @see Exchange#getException()
301         * @return an expression object which will return the exception set on the exchange
302         */
303        public static Expression exchangeExceptionExpression() {
304            return new ExpressionAdapter() {
305                public Object evaluate(Exchange exchange) {
306                    Exception exception = exchange.getException();
307                    if (exception == null) {
308                        exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
309                    }
310                    return exception;
311                }
312    
313                @Override
314                public String toString() {
315                    return "exchangeException";
316                }
317            };
318        }
319    
320        /**
321         * Returns an expression for an exception set on the exchange
322         * <p/>
323         * Is used to get the caused exception that typically have been wrapped in some sort
324         * of Camel wrapper exception
325         * @param type the exception type
326         * @see Exchange#getException(Class)
327         * @return an expression object which will return the exception set on the exchange
328         */
329        public static Expression exchangeExceptionExpression(final Class<Exception> type) {
330            return new ExpressionAdapter() {
331                public Object evaluate(Exchange exchange) {
332                    Exception exception = exchange.getException(type);
333                    if (exception == null) {
334                        exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
335                        return ObjectHelper.getException(type, exception);
336                    }
337                    return exception;
338                }
339    
340                @Override
341                public String toString() {
342                    return "exchangeException[" + type + "]";
343                }
344            };
345        }
346        
347        /**
348         * Returns the expression for the exchanges exception invoking methods defined
349         * in a simple OGNL notation
350         *
351         * @param ognl  methods to invoke on the body in a simple OGNL syntax
352         */
353        public static Expression exchangeExceptionOgnlExpression(final String ognl) {
354            return new ExpressionAdapter() {
355                public Object evaluate(Exchange exchange) {
356                    Object exception = exchange.getException();
357                    if (exception == null) {
358                        exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
359                    }
360                    
361                    if (exception == null) {
362                        return null;
363                    }
364                    return new MethodCallExpression(exception, ognl).evaluate(exchange);
365                }
366    
367                @Override
368                public String toString() {
369                    return "exchangeExceptionOgnl(" + ognl + ")";
370                }
371            };
372        }
373    
374        /**
375         * Returns an expression for the type converter
376         *
377         * @return an expression object which will return the type converter
378         */
379        public static Expression typeConverterExpression() {
380            return new ExpressionAdapter() {
381                public Object evaluate(Exchange exchange) {
382                    return exchange.getContext().getTypeConverter();
383                }
384    
385                @Override
386                public String toString() {
387                    return "typeConverter";
388                }
389            };
390        }
391    
392        /**
393         * Returns an expression for the {@link org.apache.camel.spi.Registry}
394         *
395         * @return an expression object which will return the registry
396         */
397        public static Expression registryExpression() {
398            return new ExpressionAdapter() {
399                public Object evaluate(Exchange exchange) {
400                    return exchange.getContext().getRegistry();
401                }
402    
403                @Override
404                public String toString() {
405                    return "registry";
406                }
407            };
408        }
409    
410        /**
411         * Returns an expression for lookup a bean in the {@link org.apache.camel.spi.Registry}
412         *
413         * @return an expression object which will return the bean
414         */
415        public static Expression refExpression(final String ref) {
416            return new ExpressionAdapter() {
417                public Object evaluate(Exchange exchange) {
418                    return exchange.getContext().getRegistry().lookup(ref);
419                }
420    
421                @Override
422                public String toString() {
423                    return "ref(" + ref + ")";
424                }
425            };
426        }
427    
428        /**
429         * Returns an expression for the {@link org.apache.camel.CamelContext}
430         *
431         * @return an expression object which will return the camel context
432         */
433        public static Expression camelContextExpression() {
434            return new ExpressionAdapter() {
435                public Object evaluate(Exchange exchange) {
436                    return exchange.getContext();
437                }
438    
439                @Override
440                public String toString() {
441                    return "camelContext";
442                }
443            };
444        }
445    
446        /**
447         * Returns an expression for the {@link org.apache.camel.CamelContext} name
448         *
449         * @return an expression object which will return the camel context name
450         */
451        public static Expression camelContextNameExpression() {
452            return new ExpressionAdapter() {
453                public Object evaluate(Exchange exchange) {
454                    return exchange.getContext().getName();
455                }
456    
457                @Override
458                public String toString() {
459                    return "camelContextName";
460                }
461            };
462        }
463    
464        /**
465         * Returns an expression for an exception message set on the exchange
466         *
467         * @see <tt>Exchange.getException().getMessage()</tt>
468         * @return an expression object which will return the exception message set on the exchange
469         */
470        public static Expression exchangeExceptionMessageExpression() {
471            return new ExpressionAdapter() {
472                public Object evaluate(Exchange exchange) {
473                    Exception exception = exchange.getException();
474                    if (exception == null) {
475                        exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
476                    }
477                    return exception != null ? exception.getMessage() : null;
478                }
479    
480                @Override
481                public String toString() {
482                    return "exchangeExceptionMessage";
483                }
484            };
485        }
486    
487        /**
488         * Returns an expression for an exception stacktrace set on the exchange
489         *
490         * @return an expression object which will return the exception stacktrace set on the exchange
491         */
492        public static Expression exchangeExceptionStackTraceExpression() {
493            return new ExpressionAdapter() {
494                public Object evaluate(Exchange exchange) {
495                    Exception exception = exchange.getException();
496                    if (exception == null) {
497                        exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
498                    }
499                    if (exception != null) {
500                        StringWriter sw = new StringWriter();
501                        PrintWriter pw = new PrintWriter(sw);
502                        exception.printStackTrace(pw);
503                        IOHelper.close(pw, sw);
504                        return sw.toString();
505                    } else {
506                        return null;
507                    }
508                }
509    
510                @Override
511                public String toString() {
512                    return "exchangeExceptionStackTrace";
513                }
514            };
515        }
516    
517        /**
518         * Returns an expression for the property value of exchange with the given name
519         *
520         * @param propertyName the name of the property the expression will return
521         * @return an expression object which will return the property value
522         */
523        public static Expression propertyExpression(final String propertyName) {
524            return new ExpressionAdapter() {
525                public Object evaluate(Exchange exchange) {
526                    return exchange.getProperty(propertyName);
527                }
528    
529                @Override
530                public String toString() {
531                    return "property(" + propertyName + ")";
532                }
533            };
534        }
535        
536        /**
537         * Returns an expression for the property value of exchange with the given name invoking methods defined
538         * in a simple OGNL notation
539         *
540         * @param ognl  methods to invoke on the property in a simple OGNL syntax
541         */
542        public static Expression propertyOgnlExpression(final String ognl) {
543            return new KeyedOgnlExpressionAdapter(ognl, "propertyOgnl(" + ognl + ")",
544                new KeyedOgnlExpressionAdapter.KeyedEntityRetrievalStrategy() {
545                    public Object getKeyedEntity(Exchange exchange, String key) {
546                        return exchange.getProperty(key);
547                    }
548                });
549        }
550    
551        /**
552         * Returns an expression for the properties of exchange
553         *
554         * @return an expression object which will return the properties
555         */
556        public static Expression propertiesExpression() {
557            return new ExpressionAdapter() {
558                public Object evaluate(Exchange exchange) {
559                    return exchange.getProperties();
560                }
561    
562                @Override
563                public String toString() {
564                    return "properties";
565                }
566            };
567        }
568        
569        /**
570         * Returns an expression for the properties of the camel context
571         *
572         * @return an expression object which will return the properties
573         */
574        public static Expression camelContextPropertiesExpression() {
575            return new ExpressionAdapter() {
576                public Object evaluate(Exchange exchange) {
577                    return exchange.getContext().getProperties();
578                }
579    
580                @Override
581                public String toString() {
582                    return "camelContextProperties";
583                }
584            };
585        }
586        
587        /**
588         * Returns an expression for the property value of the camel context with the given name
589         *
590         * @param propertyName the name of the property the expression will return
591         * @return an expression object which will return the property value
592         */
593        public static Expression camelContextPropertyExpression(final String propertyName) {
594            return new ExpressionAdapter() {
595                public Object evaluate(Exchange exchange) {
596                    return exchange.getContext().getProperties().get(propertyName);
597                }
598    
599                @Override
600                public String toString() {
601                    return "camelContextProperty(" + propertyName + ")";
602                }
603            };
604        }
605    
606        /**
607         * Returns an expression for a system property value with the given name
608         *
609         * @param propertyName the name of the system property the expression will return
610         * @return an expression object which will return the system property value
611         */
612        public static Expression systemPropertyExpression(final String propertyName) {
613            return systemPropertyExpression(propertyName, null);
614        }
615    
616        /**
617         * Returns an expression for a system property value with the given name
618         *
619         * @param propertyName the name of the system property the expression will return
620         * @param defaultValue default value to return if no system property exists
621         * @return an expression object which will return the system property value
622         */
623        public static Expression systemPropertyExpression(final String propertyName,
624                                                          final String defaultValue) {
625            return new ExpressionAdapter() {
626                public Object evaluate(Exchange exchange) {
627                    return System.getProperty(propertyName, defaultValue);
628                }
629    
630                @Override
631                public String toString() {
632                    return "systemProperty(" + propertyName + ")";
633                }
634            };
635        }
636    
637        /**
638         * Returns an expression for a system environment value with the given name
639         *
640         * @param propertyName the name of the system environment the expression will return
641         * @return an expression object which will return the system property value
642         */
643        public static Expression systemEnvironmentExpression(final String propertyName) {
644            return systemEnvironmentExpression(propertyName, null);
645        }
646    
647        /**
648         * Returns an expression for a system environment value with the given name
649         *
650         * @param propertyName the name of the system environment the expression will return
651         * @param defaultValue default value to return if no system environment exists
652         * @return an expression object which will return the system environment value
653         */
654        public static Expression systemEnvironmentExpression(final String propertyName,
655                                                             final String defaultValue) {
656            return new ExpressionAdapter() {
657                public Object evaluate(Exchange exchange) {
658                    String answer = System.getenv(propertyName);
659                    if (answer == null) {
660                        answer = defaultValue;
661                    }
662                    return answer;
663                }
664    
665                @Override
666                public String toString() {
667                    return "systemEnvironment(" + propertyName + ")";
668                }
669            };
670        }
671    
672        /**
673         * Returns an expression for the constant value
674         *
675         * @param value the value the expression will return
676         * @return an expression object which will return the constant value
677         */
678        public static Expression constantExpression(final Object value) {
679            return new ExpressionAdapter() {
680                public Object evaluate(Exchange exchange) {
681                    return value;
682                }
683    
684                @Override
685                public String toString() {
686                    return "" + value;
687                }
688            };
689        }
690    
691        /**
692         * Returns the expression for the exchanges inbound message body
693         */
694        public static Expression bodyExpression() {
695            return new ExpressionAdapter() {
696                public Object evaluate(Exchange exchange) {
697                    return exchange.getIn().getBody();
698                }
699    
700                @Override
701                public String toString() {
702                    return "body";
703                }
704            };
705        }
706    
707        /**
708         * Returns the expression for the exchanges inbound message body invoking methods defined
709         * in a simple OGNL notation
710         *
711         * @param ognl  methods to invoke on the body in a simple OGNL syntax
712         */
713        public static Expression bodyOgnlExpression(final String ognl) {
714            return new ExpressionAdapter() {
715                public Object evaluate(Exchange exchange) {
716                    Object body = exchange.getIn().getBody();
717                    if (body == null) {
718                        return null;
719                    }
720                    return new MethodCallExpression(body, ognl).evaluate(exchange);
721                }
722    
723                @Override
724                public String toString() {
725                    return "bodyOgnl(" + ognl + ")";
726                }
727            };
728        }
729    
730        /**
731         * Returns the expression for the exchanges inbound message body converted
732         * to the given type
733         */
734        public static <T> Expression bodyExpression(final Class<T> type) {
735            return new ExpressionAdapter() {
736                public Object evaluate(Exchange exchange) {
737                    return exchange.getIn().getBody(type);
738                }
739    
740                @Override
741                public String toString() {
742                    return "bodyAs[" + type.getName() + "]";
743                }
744            };
745        }
746    
747        /**
748         * Returns the expression for the exchanges inbound message body converted
749         * to the given type
750         */
751        public static Expression bodyExpression(final String name) {
752            return new ExpressionAdapter() {
753                public Object evaluate(Exchange exchange) {
754                    Class<?> type;
755                    try {
756                        type = exchange.getContext().getClassResolver().resolveMandatoryClass(name);
757                    } catch (ClassNotFoundException e) {
758                        throw ObjectHelper.wrapCamelExecutionException(exchange, e);
759                    }
760                    return exchange.getIn().getBody(type);
761                }
762    
763                @Override
764                public String toString() {
765                    return "bodyAs[" + name + "]";
766                }
767            };
768        }
769    
770        /**
771         * Returns the expression for the exchanges inbound message body converted
772         * to the given type
773         */
774        public static Expression mandatoryBodyExpression(final String name) {
775            return new ExpressionAdapter() {
776                public Object evaluate(Exchange exchange) {
777                    Class<?> type;
778                    try {
779                        type = exchange.getContext().getClassResolver().resolveMandatoryClass(name);
780                    } catch (ClassNotFoundException e) {
781                        throw ObjectHelper.wrapCamelExecutionException(exchange, e);
782                    }
783                    try {
784                        return exchange.getIn().getMandatoryBody(type);
785                    } catch (InvalidPayloadException e) {
786                        throw ObjectHelper.wrapCamelExecutionException(exchange, e);
787                    }
788                }
789    
790                @Override
791                public String toString() {
792                    return "mandatoryBodyAs[" + name + "]";
793                }
794            };
795        }
796    
797        /**
798         * Returns the expression for the current thread name
799         */
800        public static Expression threadNameExpression() {
801            return new ExpressionAdapter() {
802                public Object evaluate(Exchange exchange) {
803                    return Thread.currentThread().getName();
804                }
805    
806                @Override
807                public String toString() {
808                    return "threadName";
809                }
810            };
811        }
812    
813        /**
814         * Returns the expression for the exchanges inbound message body converted
815         * to the given type.
816         * <p/>
817         * Does <b>not</b> allow null bodies.
818         */
819        public static <T> Expression mandatoryBodyExpression(final Class<T> type) {
820            return mandatoryBodyExpression(type, false);
821        }
822    
823        /**
824         * Returns the expression for the exchanges inbound message body converted
825         * to the given type
826         *
827         * @param type the type
828         * @param nullBodyAllowed whether null bodies is allowed and if so a null is returned,
829         *                        otherwise an exception is thrown
830         */
831        public static <T> Expression mandatoryBodyExpression(final Class<T> type, final boolean nullBodyAllowed) {
832            return new ExpressionAdapter() {
833                public Object evaluate(Exchange exchange) {
834                    if (nullBodyAllowed) {
835                        if (exchange.getIn().getBody() == null) {
836                            return null;
837                        }
838    
839                        // if its a bean invocation then if it has no arguments then it should be threaded as null body allowed
840                        BeanInvocation bi = exchange.getIn().getBody(BeanInvocation.class);
841                        if (bi != null && (bi.getArgs() == null || bi.getArgs().length == 0 || bi.getArgs()[0] == null)) {
842                            return null;
843                        }
844                    }
845    
846                    try {
847                        return exchange.getIn().getMandatoryBody(type);
848                    } catch (InvalidPayloadException e) {
849                        throw ObjectHelper.wrapCamelExecutionException(exchange, e);
850                    }
851                }
852    
853                @Override
854                public String toString() {
855                    return "mandatoryBodyAs[" + type.getName() + "]";
856                }
857            };
858        }
859    
860        /**
861         * Returns the expression for the exchanges inbound message body type
862         */
863        public static Expression bodyTypeExpression() {
864            return new ExpressionAdapter() {
865                public Object evaluate(Exchange exchange) {
866                    return exchange.getIn().getBody().getClass();
867                }
868    
869                @Override
870                public String toString() {
871                    return "bodyType";
872                }
873            };
874        }
875    
876        /**
877         * Returns the expression for the out messages body
878         */
879        public static Expression outBodyExpression() {
880            return new ExpressionAdapter() {
881                public Object evaluate(Exchange exchange) {
882                    if (exchange.hasOut()) {
883                        return exchange.getOut().getBody();
884                    } else {
885                        return null;
886                    }
887                }
888    
889                @Override
890                public String toString() {
891                    return "outBody";
892                }
893            };
894        }
895    
896        /**
897         * Returns the expression for the exchanges outbound message body converted
898         * to the given type
899         */
900        public static <T> Expression outBodyExpression(final Class<T> type) {
901            return new ExpressionAdapter() {
902                public Object evaluate(Exchange exchange) {
903                    if (exchange.hasOut()) {
904                        return exchange.getOut().getBody(type);
905                    } else {
906                        return null;
907                    }
908                }
909    
910                @Override
911                public String toString() {
912                    return "outBodyAs[" + type.getName() + "]";
913                }
914            };
915        }
916    
917        /**
918         * Returns the expression for the fault messages body
919         */
920        public static Expression faultBodyExpression() {
921            return new ExpressionAdapter() {
922                public Object evaluate(Exchange exchange) {
923                    return exchange.getOut().isFault() ? exchange.getOut().getBody() : null;
924                }
925    
926                @Override
927                public String toString() {
928                    return "faultBody";
929                }
930            };
931        }
932    
933        /**
934         * Returns the expression for the exchanges fault message body converted
935         * to the given type
936         */
937        public static <T> Expression faultBodyExpression(final Class<T> type) {
938            return new ExpressionAdapter() {
939                public Object evaluate(Exchange exchange) {
940                    return exchange.getOut().isFault() ? exchange.getOut().getBody(type) : null;
941                }
942    
943                @Override
944                public String toString() {
945                    return "faultBodyAs[" + type.getName() + "]";
946                }
947            };
948        }
949    
950        /**
951         * Returns the expression for the exchange
952         */
953        public static Expression exchangeExpression() {
954            return new ExpressionAdapter() {
955                public Object evaluate(Exchange exchange) {
956                    return exchange;
957                }
958    
959                @Override
960                public String toString() {
961                    return "exchange";
962                }
963            };
964        }
965    
966        /**
967         * Returns the expression for the IN message
968         */
969        public static Expression inMessageExpression() {
970            return new ExpressionAdapter() {
971                public Object evaluate(Exchange exchange) {
972                    return exchange.getIn();
973                }
974    
975                @Override
976                public String toString() {
977                    return "inMessage";
978                }
979            };
980        }
981    
982        /**
983         * Returns the expression for the OUT message
984         */
985        public static Expression outMessageExpression() {
986            return new ExpressionAdapter() {
987                public Object evaluate(Exchange exchange) {
988                    return exchange.getOut();
989                }
990    
991                @Override
992                public String toString() {
993                    return "outMessage";
994                }
995            };
996        }
997    
998        /**
999         * Returns an expression which converts the given expression to the given type
1000         */
1001        public static Expression convertToExpression(final Expression expression, final Class<?> type) {
1002            return new ExpressionAdapter() {
1003                public Object evaluate(Exchange exchange) {
1004                    if (type != null) {
1005                        return expression.evaluate(exchange, type);
1006                    } else {
1007                        return expression;
1008                    }
1009                }
1010    
1011                @Override
1012                public String toString() {
1013                    return "" + expression;
1014                }
1015            };
1016        }
1017    
1018        /**
1019         * Returns an expression which converts the given expression to the given type the type
1020         * expression is evaluated to
1021         */
1022        public static Expression convertToExpression(final Expression expression, final Expression type) {
1023            return new ExpressionAdapter() {
1024                public Object evaluate(Exchange exchange) {
1025                    Object result = type.evaluate(exchange, Object.class);
1026                    if (result != null) {
1027                        return expression.evaluate(exchange, result.getClass());
1028                    } else {
1029                        return expression;
1030                    }
1031                }
1032    
1033                @Override
1034                public String toString() {
1035                    return "" + expression;
1036                }
1037            };
1038        }
1039    
1040        /**
1041         * Returns a tokenize expression which will tokenize the string with the
1042         * given token
1043         */
1044        public static Expression tokenizeExpression(final Expression expression,
1045                                                    final String token) {
1046            return new ExpressionAdapter() {
1047                public Object evaluate(Exchange exchange) {
1048                    Object value = expression.evaluate(exchange, Object.class);
1049                    Scanner scanner = ObjectHelper.getScanner(exchange, value);
1050                    scanner.useDelimiter(token);
1051                    return scanner;
1052                }
1053    
1054                @Override
1055                public String toString() {
1056                    return "tokenize(" + expression + ", " + token + ")";
1057                }
1058            };
1059        }
1060    
1061        /**
1062         * Returns an {@link TokenPairExpressionIterator} expression
1063         */
1064        public static Expression tokenizePairExpression(String startToken, String endToken, boolean includeTokens) {
1065            return new TokenPairExpressionIterator(startToken, endToken, includeTokens);
1066        }
1067    
1068        /**
1069         * Returns an {@link TokenXMLPairExpressionIterator} expression
1070         */
1071        public static Expression tokenizeXMLExpression(String tagName, String inheritNamespaceTagName) {
1072            ObjectHelper.notEmpty(tagName, "tagName");
1073    
1074            // must be XML tokens
1075            if (!tagName.startsWith("<")) {
1076                tagName = "<" + tagName;
1077            }
1078            if (!tagName.endsWith(">")) {
1079                tagName = tagName + ">";
1080            }
1081    
1082            String endToken = "</" + tagName.substring(1);
1083    
1084            if (inheritNamespaceTagName != null) {
1085                if (!inheritNamespaceTagName.startsWith("<")) {
1086                    inheritNamespaceTagName = "<" + inheritNamespaceTagName;
1087                }
1088                if (!inheritNamespaceTagName.endsWith(">")) {
1089                    inheritNamespaceTagName = inheritNamespaceTagName + ">";
1090                }
1091            }
1092    
1093            return new TokenXMLPairExpressionIterator(tagName, endToken, inheritNamespaceTagName);
1094        }
1095    
1096        /**
1097         * Returns a tokenize expression which will tokenize the string with the
1098         * given regex
1099         */
1100        public static Expression regexTokenizeExpression(final Expression expression,
1101                                                         final String regexTokenizer) {
1102            final Pattern pattern = Pattern.compile(regexTokenizer);
1103            return new ExpressionAdapter() {
1104                public Object evaluate(Exchange exchange) {
1105                    Object value = expression.evaluate(exchange, Object.class);
1106                    Scanner scanner = ObjectHelper.getScanner(exchange, value);
1107                    scanner.useDelimiter(pattern);
1108                    return scanner;
1109                }
1110    
1111                @Override
1112                public String toString() {
1113                    return "regexTokenize(" + expression + ", " + pattern.pattern() + ")";
1114                }
1115            };
1116        }
1117    
1118        public static Expression groupIteratorExpression(final Expression expression, final String token, final int group) {
1119            return new ExpressionAdapter() {
1120                public Object evaluate(Exchange exchange) {
1121                    // evaluate expression as iterator
1122                    Iterator<?> it = expression.evaluate(exchange, Iterator.class);
1123                    ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator");
1124                    return new GroupIterator(exchange.getContext(), it, token, group);
1125                }
1126    
1127                @Override
1128                public String toString() {
1129                    return "group " + expression + " " + group + " times";
1130                }
1131            };
1132        }
1133    
1134        /**
1135         * Returns a sort expression which will sort the expression with the given comparator.
1136         * <p/>
1137         * The expression is evaluated as a {@link List} object to allow sorting.
1138         */
1139        @SuppressWarnings({"unchecked", "rawtypes"})
1140        public static Expression sortExpression(final Expression expression, final Comparator comparator) {
1141            return new ExpressionAdapter() {
1142                public Object evaluate(Exchange exchange) {
1143                    List<?> list = expression.evaluate(exchange, List.class);
1144                    Collections.sort(list, comparator);
1145                    return list;
1146                }
1147    
1148                @Override
1149                public String toString() {
1150                    return "sort(" + expression + " by: " + comparator + ")";
1151                }
1152            };
1153        }
1154    
1155        /**
1156         * Transforms the expression into a String then performs the regex
1157         * replaceAll to transform the String and return the result
1158         */
1159        public static Expression regexReplaceAll(final Expression expression,
1160                                                 final String regex, final String replacement) {
1161            final Pattern pattern = Pattern.compile(regex);
1162            return new ExpressionAdapter() {
1163                public Object evaluate(Exchange exchange) {
1164                    String text = expression.evaluate(exchange, String.class);
1165                    if (text == null) {
1166                        return null;
1167                    }
1168                    return pattern.matcher(text).replaceAll(replacement);
1169                }
1170    
1171                @Override
1172                public String toString() {
1173                    return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")";
1174                }
1175            };
1176        }
1177    
1178        /**
1179         * Transforms the expression into a String then performs the regex
1180         * replaceAll to transform the String and return the result
1181         */
1182        public static Expression regexReplaceAll(final Expression expression,
1183                                                 final String regex, final Expression replacementExpression) {
1184    
1185            final Pattern pattern = Pattern.compile(regex);
1186            return new ExpressionAdapter() {
1187                public Object evaluate(Exchange exchange) {
1188                    String text = expression.evaluate(exchange, String.class);
1189                    String replacement = replacementExpression.evaluate(exchange, String.class);
1190                    if (text == null || replacement == null) {
1191                        return null;
1192                    }
1193                    return pattern.matcher(text).replaceAll(replacement);
1194                }
1195    
1196                @Override
1197                public String toString() {
1198                    return "regexReplaceAll(" + expression + ", " + pattern.pattern() + ")";
1199                }
1200            };
1201        }
1202    
1203        /**
1204         * Appends the String evaluations of the two expressions together
1205         */
1206        public static Expression append(final Expression left, final Expression right) {
1207            return new ExpressionAdapter() {
1208                public Object evaluate(Exchange exchange) {
1209                    return left.evaluate(exchange, String.class) + right.evaluate(exchange, String.class);
1210                }
1211    
1212                @Override
1213                public String toString() {
1214                    return "append(" + left + ", " + right + ")";
1215                }
1216            };
1217        }
1218    
1219        /**
1220         * Prepends the String evaluations of the two expressions together
1221         */
1222        public static Expression prepend(final Expression left, final Expression right) {
1223            return new ExpressionAdapter() {
1224                public Object evaluate(Exchange exchange) {
1225                    return right.evaluate(exchange, String.class) + left.evaluate(exchange, String.class);
1226                }
1227    
1228                @Override
1229                public String toString() {
1230                    return "prepend(" + left + ", " + right + ")";
1231                }
1232            };
1233        }
1234    
1235        /**
1236         * Returns an expression which returns the string concatenation value of the various
1237         * expressions
1238         *
1239         * @param expressions the expression to be concatenated dynamically
1240         * @return an expression which when evaluated will return the concatenated values
1241         */
1242        public static Expression concatExpression(final Collection<Expression> expressions) {
1243            return concatExpression(expressions, null);
1244        }
1245    
1246        /**
1247         * Returns an expression which returns the string concatenation value of the various
1248         * expressions
1249         *
1250         * @param expressions the expression to be concatenated dynamically
1251         * @param expression the text description of the expression
1252         * @return an expression which when evaluated will return the concatenated values
1253         */
1254        public static Expression concatExpression(final Collection<Expression> expressions, final String expression) {
1255            return new ExpressionAdapter() {
1256                public Object evaluate(Exchange exchange) {
1257                    StringBuilder buffer = new StringBuilder();
1258                    for (Expression expression : expressions) {
1259                        String text = expression.evaluate(exchange, String.class);
1260                        if (text != null) {
1261                            buffer.append(text);
1262                        }
1263                    }
1264                    return buffer.toString();
1265                }
1266    
1267                @Override
1268                public String toString() {
1269                    if (expression != null) {
1270                        return expression;
1271                    } else {
1272                        return "concat" + expressions;
1273                    }
1274                }
1275            };
1276        }
1277    
1278        /**
1279         * Returns an Expression for the inbound message id
1280         */
1281        public static Expression messageIdExpression() {
1282            return new ExpressionAdapter() {
1283                public Object evaluate(Exchange exchange) {
1284                    return exchange.getIn().getMessageId();
1285                }
1286    
1287                @Override
1288                public String toString() {
1289                    return "messageId";
1290                }
1291            };
1292        }
1293    
1294        /**
1295         * Returns an Expression for the exchange id
1296         */
1297        public static Expression exchangeIdExpression() {
1298            return new ExpressionAdapter() {
1299                public Object evaluate(Exchange exchange) {
1300                    return exchange.getExchangeId();
1301                }
1302    
1303                @Override
1304                public String toString() {
1305                    return "exchangeId";
1306                }
1307            };
1308        }
1309    
1310        public static Expression dateExpression(final String command, final String pattern) {
1311            return new ExpressionAdapter() {
1312                public Object evaluate(Exchange exchange) {
1313                    Date date;
1314                    if ("now".equals(command)) {
1315                        date = new Date();
1316                    } else if (command.startsWith("header.") || command.startsWith("in.header.")) {
1317                        String key = command.substring(command.lastIndexOf('.') + 1);
1318                        date = exchange.getIn().getHeader(key, Date.class);
1319                        if (date == null) {
1320                            throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command);
1321                        }
1322                    } else if (command.startsWith("out.header.")) {
1323                        String key = command.substring(command.lastIndexOf('.') + 1);
1324                        date = exchange.getOut().getHeader(key, Date.class);
1325                        if (date == null) {
1326                            throw new IllegalArgumentException("Cannot find java.util.Date object at command: " + command);
1327                        }
1328                    } else if ("file".equals(command)) {
1329                        date = exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Date.class);
1330                        if (date == null) {
1331                            throw new IllegalArgumentException("Cannot find " + Exchange.FILE_LAST_MODIFIED + " header at command: " + command);
1332                        }
1333                    } else {
1334                        throw new IllegalArgumentException("Command not supported for dateExpression: " + command);
1335                    }
1336    
1337                    SimpleDateFormat df = new SimpleDateFormat(pattern);
1338                    return df.format(date);
1339                }
1340    
1341                @Override
1342                public String toString() {
1343                    return "date(" + command + ":" + pattern + ")";
1344                }
1345            };
1346        }
1347    
1348        public static Expression simpleExpression(final String expression) {
1349            return new ExpressionAdapter() {
1350                public Object evaluate(Exchange exchange) {
1351                    // resolve language using context to have a clear separation of packages
1352                    // must call evaluate to return the nested language evaluate when evaluating
1353                    // stacked expressions
1354                    Language language = exchange.getContext().resolveLanguage("simple");
1355                    return language.createExpression(expression).evaluate(exchange, Object.class);
1356                }
1357    
1358                @Override
1359                public String toString() {
1360                    return "simple(" + expression + ")";
1361                }
1362            };
1363        }
1364       
1365        public static Expression beanExpression(final String expression) {
1366            return new ExpressionAdapter() {
1367                public Object evaluate(Exchange exchange) {
1368                    // resolve language using context to have a clear separation of packages
1369                    // must call evaluate to return the nested language evaluate when evaluating
1370                    // stacked expressions
1371                    Language language = exchange.getContext().resolveLanguage("bean");
1372                    return language.createExpression(expression).evaluate(exchange, Object.class);
1373                }
1374    
1375                @Override
1376                public String toString() {
1377                    return "bean(" + expression + ")";
1378                }
1379            };
1380        }
1381        
1382        public static Expression beanExpression(final Class<?> beanType, final String methodName) {
1383            return BeanLanguage.bean(beanType, methodName);        
1384        }
1385    
1386        public static Expression beanExpression(final Object bean, final String methodName) {
1387            return BeanLanguage.bean(bean, methodName);        
1388        }
1389    
1390        public static Expression beanExpression(final String beanRef, final String methodName) {
1391            String expression = methodName != null ? beanRef + "." + methodName : beanRef;
1392            return beanExpression(expression);
1393        }
1394    
1395        /**
1396         * Returns an expression processing the exchange to the given endpoint uri
1397         *
1398         * @param uri endpoint uri to send the exchange to
1399         * @return an expression object which will return the OUT body
1400         */
1401        public static Expression toExpression(final String uri) {
1402            return new ExpressionAdapter() {
1403                public Object evaluate(Exchange exchange) {
1404                    Endpoint endpoint = exchange.getContext().getEndpoint(uri);
1405                    if (endpoint == null) {
1406                        throw new NoSuchEndpointException(uri);
1407                    }
1408    
1409                    Producer producer;
1410                    try {
1411                        producer = endpoint.createProducer();
1412                        producer.start();
1413                        producer.process(exchange);
1414                        producer.stop();
1415                    } catch (Exception e) {
1416                        throw ObjectHelper.wrapRuntimeCamelException(e);
1417                    }
1418    
1419                    // return the OUT body, but check for exchange pattern
1420                    if (ExchangeHelper.isOutCapable(exchange)) {
1421                        return exchange.getOut().getBody();
1422                    } else {
1423                        return exchange.getIn().getBody();
1424                    }
1425                }
1426    
1427                @Override
1428                public String toString() {
1429                    return "to(" + uri + ")";
1430                }
1431            };
1432        }
1433    
1434        public static Expression fileNameExpression() {
1435            return new ExpressionAdapter() {
1436                public Object evaluate(Exchange exchange) {
1437                    return exchange.getIn().getHeader(Exchange.FILE_NAME, String.class);
1438                }
1439    
1440                @Override
1441                public String toString() {
1442                    return "file:name";
1443                }
1444            };
1445        }
1446    
1447        public static Expression fileOnlyNameExpression() {
1448            return new ExpressionAdapter() {
1449                public Object evaluate(Exchange exchange) {
1450                    String answer = exchange.getIn().getHeader(Exchange.FILE_NAME_ONLY, String.class);
1451                    if (answer == null) {
1452                        answer = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class);
1453                        answer = FileUtil.stripPath(answer);
1454                    }
1455                    return answer;
1456                }
1457    
1458                @Override
1459                public String toString() {
1460                    return "file:onlyname";
1461                }
1462            };
1463        }
1464    
1465        public static Expression fileNameNoExtensionExpression() {
1466            return new ExpressionAdapter() {
1467                public Object evaluate(Exchange exchange) {
1468                    String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class);
1469                    return FileUtil.stripExt(name);
1470                }
1471    
1472                @Override
1473                public String toString() {
1474                    return "file:name.noext";
1475                }
1476            };
1477        }
1478    
1479        public static Expression fileOnlyNameNoExtensionExpression() {
1480            return new ExpressionAdapter() {
1481                public Object evaluate(Exchange exchange) {
1482                    String name = fileOnlyNameExpression().evaluate(exchange, String.class);
1483                    return FileUtil.stripExt(name);
1484                }
1485    
1486                @Override
1487                public String toString() {
1488                    return "file:onlyname.noext";
1489                }
1490            };
1491        }
1492    
1493        public static Expression fileExtensionExpression() {
1494            return new ExpressionAdapter() {
1495                public Object evaluate(Exchange exchange) {
1496                    String name = exchange.getIn().getHeader(Exchange.FILE_NAME, String.class);
1497                    if (name != null) {
1498                        return name.substring(name.lastIndexOf('.') + 1);
1499                    } else {
1500                        return null;
1501                    }
1502                }
1503    
1504                @Override
1505                public String toString() {
1506                    return "file:ext";
1507                }
1508            };
1509        }
1510    
1511        public static Expression fileParentExpression() {
1512            return new ExpressionAdapter() {
1513                public Object evaluate(Exchange exchange) {
1514                    return exchange.getIn().getHeader("CamelFileParent", String.class);
1515                }
1516    
1517                @Override
1518                public String toString() {
1519                    return "file:parent";
1520                }
1521            };
1522        }
1523    
1524        public static Expression filePathExpression() {
1525            return new ExpressionAdapter() {
1526                public Object evaluate(Exchange exchange) {
1527                    return exchange.getIn().getHeader("CamelFilePath", String.class);
1528                }
1529    
1530                @Override
1531                public String toString() {
1532                    return "file:path";
1533                }
1534            };
1535        }
1536    
1537        public static Expression fileAbsolutePathExpression() {
1538            return new ExpressionAdapter() {
1539                public Object evaluate(Exchange exchange) {
1540                    return exchange.getIn().getHeader("CamelFileAbsolutePath", String.class);
1541                }
1542    
1543                @Override
1544                public String toString() {
1545                    return "file:absolute.path";
1546                }
1547            };
1548        }
1549    
1550        public static Expression fileAbsoluteExpression() {
1551            return new ExpressionAdapter() {
1552                public Object evaluate(Exchange exchange) {
1553                    return exchange.getIn().getHeader("CamelFileAbsolute", Boolean.class);
1554                }
1555    
1556                @Override
1557                public String toString() {
1558                    return "file:absolute";
1559                }
1560            };
1561        }
1562    
1563        public static Expression fileSizeExpression() {
1564            return new ExpressionAdapter() {
1565                public Object evaluate(Exchange exchange) {
1566                    return exchange.getIn().getHeader("CamelFileLength", Long.class);
1567                }
1568    
1569                @Override
1570                public String toString() {
1571                    return "file:length";
1572                }
1573            };
1574        }
1575    
1576        public static Expression fileLastModifiedExpression() {
1577            return new ExpressionAdapter() {
1578                public Object evaluate(Exchange exchange) {
1579                    return exchange.getIn().getHeader(Exchange.FILE_LAST_MODIFIED, Date.class);
1580                }
1581    
1582                @Override
1583                public String toString() {
1584                    return "file:modified";
1585                }
1586            };
1587        }
1588    
1589        public static Expression propertiesComponentExpression(final String key, final String locations) {
1590            return new ExpressionAdapter() {
1591                public Object evaluate(Exchange exchange) {
1592                    try {
1593                        if (locations != null) {
1594                            // the properties component is optional as we got locations
1595                            // getComponent will create a new component if none already exists
1596                            Component component = exchange.getContext().getComponent("properties");
1597                            PropertiesComponent pc = exchange.getContext().getTypeConverter()
1598                                    .mandatoryConvertTo(PropertiesComponent.class, component);
1599                            // enclose key with {{ }} to force parsing
1600                            String[] paths = locations.split(",");
1601                            return pc.parseUri(pc.getPrefixToken() + key + pc.getSuffixToken(), paths);
1602                        } else {
1603                            // the properties component is mandatory if no locations provided
1604                            Component component = exchange.getContext().hasComponent("properties");
1605                            if (component == null) {
1606                                throw new IllegalArgumentException("PropertiesComponent with name properties must be defined"
1607                                        + " in CamelContext to support property placeholders in expressions");
1608                            }
1609                            PropertiesComponent pc = exchange.getContext().getTypeConverter()
1610                                    .mandatoryConvertTo(PropertiesComponent.class, component);
1611                            // enclose key with {{ }} to force parsing
1612                            return pc.parseUri(pc.getPrefixToken() + key + pc.getSuffixToken());
1613                        }
1614                    } catch (Exception e) {
1615                        throw ObjectHelper.wrapRuntimeCamelException(e);
1616                    }
1617                }
1618    
1619                @Override
1620                public String toString() {
1621                    return "properties(" + key + ")";
1622                }
1623            };
1624        }
1625    
1626        /**
1627         * Expression adapter for OGNL expression from Message Header or Exchange property
1628         */
1629        private static class KeyedOgnlExpressionAdapter extends ExpressionAdapter {
1630            private final String ognl;
1631            private final String toStringValue;
1632            private final KeyedEntityRetrievalStrategy keyedEntityRetrievalStrategy;
1633    
1634            public KeyedOgnlExpressionAdapter(String ognl, String toStringValue, 
1635                                              KeyedEntityRetrievalStrategy keyedEntityRetrievalStrategy) {
1636                this.ognl = ognl;
1637                this.toStringValue = toStringValue;
1638                this.keyedEntityRetrievalStrategy = keyedEntityRetrievalStrategy;
1639            }
1640    
1641            public Object evaluate(Exchange exchange) {
1642                // try with full name first
1643                Object property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, ognl);
1644                if (property != null) {
1645                    return property;
1646                }
1647    
1648                // Split ognl except when this is not a Map, Array
1649                // and we would like to keep the dots within the key name
1650                List<String> methods = OgnlHelper.splitOgnl(ognl);
1651    
1652                // remove any OGNL operators so we got the pure key name
1653                String key = OgnlHelper.removeOperators(methods.get(0));
1654    
1655                property = keyedEntityRetrievalStrategy.getKeyedEntity(exchange, key);
1656                if (property == null) {
1657                    return null;
1658                }
1659                // the remainder is the rest of the ognl without the key
1660                String remainder = ObjectHelper.after(ognl, key);
1661                return new MethodCallExpression(property, remainder).evaluate(exchange);
1662            }
1663    
1664            @Override
1665            public String toString() {
1666                return toStringValue;
1667            }
1668    
1669            /**
1670             * Strategy to retrieve the value based on the key
1671             */
1672            public interface KeyedEntityRetrievalStrategy {
1673                Object getKeyedEntity(Exchange exchange, String key);
1674            }
1675        };
1676    
1677    }