commons-jexl-2.1.1-src/BUILDING.txt100644 0 0 716 11673634326 13777 0ustar 0 0 Jexl 2.0 uses Maven 2 as the build tool, and requires Java 1.5 (or later). The following goals may be useful: * mvn clean - clean up * mvn test - compile and run the unit tests * mvn site - create the documentation * mvn package - build the jar * mvn install - build the jar and install in local maven repository N.B. When building under Java 1.5, you will need to provide access to an implementation of JSR-223 (javax.script), for example BSF 3.0. commons-jexl-2.1.1-src/LICENSE.txt100644 0 0 26450 11673634316 13726 0ustar 0 0 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. commons-jexl-2.1.1-src/NOTICE.txt100644 0 0 262 11673634316 13556 0ustar 0 0 Apache Commons JEXL Copyright 2001-2011 The Apache Software Foundation This product includes software developed by The Apache Software Foundation (http://www.apache.org/). commons-jexl-2.1.1-src/pom.xml100644 0 0 27744 11673634326 13430 0ustar 0 0 org.apache.commons commons-parent 22 4.0.0 org.apache.commons commons-jexl 2.1.1 Commons JEXL 2001 The Commons Jexl library is an implementation of the JSTL Expression Language with extensions. http://commons.apache.org/jexl/ jira http://issues.apache.org/jira/browse/JEXL scm:svn:http://svn.apache.org/repos/asf/commons/proper/jexl/tags/COMMONS_JEXL_2_1_1 scm:svn:https://svn.apache.org/repos/asf/commons/proper/jexl/tags/COMMONS_JEXL_2_1_1 http://svn.apache.org/viewvc/commons/proper/jexl/tags/COMMONS_JEXL_2_1_1 people.apache.org Commons Jexl scp://people.apache.org/www/commons.apache.org/jexl dIon Gillard dion dion AT apache DOT org Apache Software Foundation Geir Magnusson Jr. geirm geirm AT apache DOT org independent Tim O'Brien tobrien tobrien AT apache DOT org independent Peter Royal proyal proyal AT apache DOT org Apache Software Foundation James Strachan jstrachan jstrachan AT apache DOT org SpiritSoft, Inc. Rahul Akolkar rahul rahul AT apache DOT org Apache Software Foundation Sebastian Bazley sebb sebb AT apache DOT org Henri Biestro henrib henrib AT apache DOT org commons-logging commons-logging 1.1.1 junit junit 4.10 test org.apache.bsf bsf-api 3.1 provided 1.5 1.5 jexl 2.1.1 RC1 1.1 JEXL 12310479 org.apache.maven.plugins maven-compiler-plugin org.apache.maven.plugins maven-surefire-plugin **/*Test.java maven-assembly-plugin src/main/assembly/bin.xml src/main/assembly/src.xml gnu org.codehaus.mojo javacc-maven-plugin 2.6 jexl-jjtree ${basedir}/src/main/java/org/apache/commons/jexl2/parser ${project.build.directory}/generated-sources/java ${project.build.directory}/generated-sources/javacc-timestamp org.apache.commons.jexl2.parser jjtree-javacc org.apache.maven.plugins maven-jar-plugin test-jar org.apache.maven.plugins maven-changes-plugin ${commons.changes.version} ${basedir}/src/site/xdoc/changes.xml %URL%/%ISSUE% changes-report org.apache.maven.plugins maven-checkstyle-plugin 2.7 ${basedir}/src/main/config/checkstyle.xml org/apache/commons/jexl2/parser/*.java ${basedir}/src/main/config/header.txt false org.codehaus.mojo cobertura-maven-plugin 2.5.1 **/generated-sources/**/* **/generated-sources/**/* org/apache/commons/jexl2/parser/*.class org/apache/commons/jexl2/**/*Test.class org.codehaus.mojo findbugs-maven-plugin 2.3.2 ${basedir}/src/main/config/findbugs-exclude-filter.xml true target/site org.apache.maven.plugins maven-pmd-plugin 2.5 1.5 **/generated-sources/**/* /rulesets/braces.xml /rulesets/unusedcode.xml /rulesets/imports.xml /rulesets/codesize.xml /rulesets/coupling.xml /rulesets/design.xml /rulesets/strings.xml org.codehaus.mojo clirr-maven-plugin org/apache/commons/jexl2/parser/** org/apache/commons/jexl2/internal/** commons-jexl-2.1.1-src/RELEASE-NOTES.txt100644 0 0 25377 11673634316 14621 0ustar 0 0 $Id: RELEASE-NOTES.txt 1215331 2011-12-16 23:04:37Z sebb $ Commons JEXL Package Version 2.1.1 Release Notes INTRODUCTION: ============= The Apache Commons JEXL library facilitates the implementation of dynamic and scripting features in applications and frameworks written in Java. JEXL implements an Expression Language based on some extensions to the JSTL Expression Language supporting most of the constructs seen in shell-script or ECMAScript. Its goal is to expose scripting features usable by technical operatives or consultants working with enterprise platforms. http://commons.apache.org/jexl/ What's new in 2.1.1 =================== Version 2.1.1 is a bugfix release to address a regression in 2.1: * JEXL-124: Array parameters to methods don't work anymore There are no other changes Compatibility with previous releases ==================================== Version 2.1 is binary compatible with 2.0.1. However it is not source compatible. New methods have been added to the org.apache.commons.jexl2.Script and org.apache.commons.jexl2.JexlInfo interfaces. Any source code that implements these interfaces will need to be updated. What's new in 2.1: ================== * A more thorough arithmetic (JexlArithmetic) that allows fine control over decimals (scale and precision), a new syntax for numeric literals (OGNL inspired Big and Huge notations) and a better type handling keeping the most appropriate representation in casual operations. * The introduction of script variables and parameters that reduce context dependencies and methods; this allows to perform checks after script creation (light static checking hints). Plus the ability to call script from scripts. * A sandoxing feature to restrict and rename what JEXL can access from the environment allowing tighter control over security. * Extensions to UnifiedJEXL that allow the creation of templates. New features in 2.1: ==================== * JEXL-121: Add simple template features [this was missing from the previous edition of these notes] * JEXL-114: Allow scripts to create local variables // Add return keyword * JEXL-113: Add functions to extract which variables, parameters and local variables are used to evaluate a script * JEXL-118: Provide an IN operator * JEXL-115: Add support for asynchronous script execution and cancellation * JEXL-116: Add control over classes, methods, constructors and properties allowed in scripts * JEXL-120: Add simple template features * JEXL-119: Allow indexed properties container resolution in expressions * JEXL-106: When divide two BigDecimal values in an expression it results in java.lang.ArithmeticException * JEXL-102: Add "jexl2" as a supported name Bugs Fixed in 2.1: ================== * JEXL-83: Make JexlArithmetic immutable (and threadsafe) * JEXL-24: Support Long for integer literal instead of Integers * JEXL-107: literals and parenthesized expressions can not be used as references * JEXL-108: parsing error if i define a empty literal array/map * JEXL-101: Vararg methods where the first argument is no vararg can not be called with only the fixed parameters given * JEXL-105: Array literals are considered constant even when they are not * JEXL-104: NPE in JexlArithmetic when an Array-Expression containing a null is used. * JEXL-112: Cannot parse Integer.MIN_VALUE * JEXL-111: expression execute error Bugs fixed in 2.0.1: ==================== * JEXL-100: Array access expressions fail when evaluated twice and cache is enabled * JEXL-99: Documentation of Thread Safety / Invalid code examples on homepage * JEXL-98: Quote escaping cannot be escaped Previous Releases: ================== Bugs fixed in 2.0: ================== * JEXL-90: Jexl parser allows invalid expressions, e.g. "a=1 b=2 3" * JEXL-88: MethodKey.java - name clash getMostSpecific() with Java 1.5.0 * JEXL-87: Inconsistent behaviour of arithmetical operations * JEXL-81: Introspector does not use ListGetExecutor for List * JEXL-80: Lenient mode should not throw exception when {g,s}etting an undefined property * JEXL-78: Ternary operator throws Exception when JexlEngine in strict mode * JEXL-76: Remove unnecessary class VisitorAdapter * JEXL-71: Parsing errors? * JEXL-67: Potential NPE in util.introspection.MethodKey * JEXL-66: testDottedNames expects map enumeration order * JEXL-64: Inconsistent behaviour of dotted names * JEXL-62: NPE in Interpreter * JEXL-59: ClassMap holds a reference to class * JEXL-56: Logging wrongly uses java.util.logging * JEXL-50: Div operator does not do integer division * JEXL-49: Block statements aren't parsed * JEXL-48: NPE during expression evaluation * JEXL-45: Unhandled division by zero * JEXL-42: NullPointerException evaluating an expression * JEXL-40: JEXL fails to find abstract public methods in the base class if overridden by non-public derived types * JEXL-32: BigDecimal values are treated as Long values which results in loss of precision * JEXL-30: ASTAddNode does not add BigDecimal objects correctly * JEXL-27: Cannot assign a value to the property of an object, such as object.prop = value. * JEXL-26: ASTArrayAccess messes up on fallback to JexlContext * JEXL-19: Ternary conditional not supported * JEXL-3 : Static method resolution and changes to context Other issues fixed (Improvements/New Features): =============================================== * JEXL-95: Enhance JSR-223 implementation * JEXL-94: Allow stateful namespaces (ns:function) * JEXL-93: Add public fields as targets of set/get property * JEXL-92: JexlContext API should be more flexible * JEXL-89: Drop main() and suite() methods from Test cases * JEXL-85: 2.0 grammar finishing touches & debugger update * JEXL-82: Change foreach syntax * JEXL-77: Rename last Velocity originated classes * JEXL-72: Remove deprecated classes and methods entirely * JEXL-70: Add main class to allow scripts etc to be tested * JEXL-63: JSR-223 support * JEXL-61: Usage of strong references on Method/Constructor & WeakHashMap usage * JEXL-60: Refactor o.a.c.jexl.util and o.a.c.jexl.util.introspection * JEXL-58: UnifiedJEXL * JEXL-57: Change pom.xml to make it Netbeans Maven2 plugin friendly * JEXL-55: JEXL 2.0 redux, attempting to restart the effort to release 2.0 * JEXL-54: Light performance enhancements * JEXL-47: Allow single-line comments with // * JEXL-43: Website overview does not mention method calls and new 2.0 features * JEXL-41: Allow nested ${} evaluation * JEXL-35: Final API requirements * JEXL-34: Remove pre and post resolution of variables via the JexlExprResolver classes. * JEXL-33: Remove unnecessary throws Exception from various classes * JEXL-29: Support non-object-level functions/methods, as size and empty function * JEXL-25: Call method with varargs * JEXL-24: Support Long for integer literal instead of Integers * JEXL-21: operator overloading / hooks on operator processing * JEXL-16: allowing quote escaping * JEXL-15: Needs definable functions * JEXL-11: Don't make null convertible into anything * JEXL-10: Make possible checking for unresolved variables Other Changes: ============== o Add @since 2.0 tags to code so we can track API additions via Javadoc Upgrading from JEXL 1.x ======================= JEXL now requires Java 1.5 or later. Version 2.0 resides in the org.apache.commons.jexl2 package; part of the version 1.x API is reimplemented as an add-on source library in the jexl-compat directory; since it can not fully reimplement the original public 1.x, it may only be used to ease transition in strictly controlled deployments. The following classes are implemented through the jexl-compat source library: * ExpressionFactory * ScriptFactory * Expression * Script * JexlContext * JexlHelper Migration notes =============== When migrating from jexl 1.x to jexl 2.0, the following hints may be helpfull. The following classes no longer exist: * ExpressionFactory, ScriptFactory: create a JexlEngine and use createExpression() or createScript() instead. The following classes have been renamed and replaced: * VelMethod <=> JexlMethod * VelPropertyGet <=> JexlPropertyGet * VelPropertySet <=> JexlPropertySet The following methods have been removed: * Info.getTemplateName() - use Info.getName() instead * Expression.addPostResolver() / Expression.addPreResolver() - set ant-like variables in JexlContext, implement a specific JexlContext or derive JexlcontextInterpreter/JexlEngine instead Behavior changes ================ * Public fields are considered when using JexlPropertyGet / JexlPropertySet: Jexl 1.x behavior can be reimplemented by subclassing UberspectImpl. *Division (/ operator) behavior change: division between integers no longer casts its operands to double; integer division allways results in a integer. The 1.x behavior can be reimplemented by subclassing JexlArithmetic. New Features: ============= Assignment expression: a = b (and a.b.c = d) * Assigns a variable (ant-like variable or bean-property) Ternary operator expression: a ? b : c (and a ?: c) * The usual inline conditional shortcut and its 'Elvis' form (a ?: b evaluates as a ? a : b) Constructor call expression: new('my.class.name', arguments...) * Creates a new instance of a class using the most appropriate constructor according to the actual arguments Function namespace: ns:func(arguments...) * A function namespace allows the use of class or instance methods in function calls UnifiedJEXL * Adds ${...} and #{...} JSP/EL syntax support on top of the JexlEngine JSR-223 support * Implement JSR-223 Scripting Engine for JEXL script (need BSF-3.0 on Java < 6) Error and exception handling * Configuring the leniency and verbosity of the Jexl engine allows user control over the error handling policy commons-jexl-2.1.1-src/src/ 40755 0 0 0 11673634325 12546 5ustar 0 0 commons-jexl-2.1.1-src/src/main/ 40755 0 0 0 11673634325 13472 5ustar 0 0 commons-jexl-2.1.1-src/src/main/assembly/ 40755 0 0 0 11673634321 15305 5ustar 0 0 commons-jexl-2.1.1-src/src/main/config/ 40755 0 0 0 11673634325 14737 5ustar 0 0 commons-jexl-2.1.1-src/src/main/java/ 40755 0 0 0 11673634321 14407 5ustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/ 40755 0 0 0 11673634321 15176 5ustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/ 40755 0 0 0 11673634321 16417 5ustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/commons/ 40755 0 0 0 11673634321 20072 5ustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/ 40755 0 0 0 11673634324 21121 5ustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/ 40755 0 0 0 11673634325 22736 5ustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/introspection/ 40755 0 0 0 11673634325 25636 5ustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/introspection/ 40755 0 0 0 11673634323 24020 5ustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ 40755 0 0 0 11673634323 22414 5ustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/scripting/ 40755 0 0 0 11673634324 23123 5ustar 0 0 commons-jexl-2.1.1-src/src/main/resources/ 40755 0 0 0 11673634325 15504 5ustar 0 0 commons-jexl-2.1.1-src/src/main/resources/META-INF/ 40755 0 0 0 11673634325 16644 5ustar 0 0 commons-jexl-2.1.1-src/src/main/resources/META-INF/services/ 40755 0 0 0 11673634325 20467 5ustar 0 0 commons-jexl-2.1.1-src/src/site/ 40755 0 0 0 11673634325 13512 5ustar 0 0 commons-jexl-2.1.1-src/src/site/resources/ 40755 0 0 0 11673634325 15524 5ustar 0 0 commons-jexl-2.1.1-src/src/site/resources/images/ 40755 0 0 0 11673634325 16771 5ustar 0 0 commons-jexl-2.1.1-src/src/site/xdoc/ 40755 0 0 0 11673634326 14450 5ustar 0 0 commons-jexl-2.1.1-src/src/site/xdoc/reference/ 40755 0 0 0 11673634326 16406 5ustar 0 0 commons-jexl-2.1.1-src/src/test/ 40755 0 0 0 11673634321 13521 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/ 40755 0 0 0 11673634317 14447 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/ 40755 0 0 0 11673634317 15236 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/ 40755 0 0 0 11673634317 16457 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/ 40755 0 0 0 11673634317 20132 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/ 40755 0 0 0 11673634321 21151 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/examples/ 40755 0 0 0 11673634321 22767 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/internal/ 40755 0 0 0 11673634320 22764 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/internal/introspection/ 40755 0 0 0 11673634321 25665 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/junit/ 40755 0 0 0 11673634317 22307 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/parser/ 40755 0 0 0 11673634320 22444 5ustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/scripting/ 40755 0 0 0 11673634320 23152 5ustar 0 0 commons-jexl-2.1.1-src/src/test/scripts/ 40755 0 0 0 11673634321 15210 5ustar 0 0 commons-jexl-2.1.1-src/src/main/assembly/bin.xml100644 0 0 3135 11673634321 16676 0ustar 0 0 bin tar.gz zip false LICENSE.txt NOTICE.txt RELEASE-NOTES.txt target *.jar target/site/apidocs apidocs commons-jexl-2.1.1-src/src/main/assembly/src.xml100644 0 0 3144 11673634321 16715 0ustar 0 0 src tar.gz zip ${artifactId}-${commons.release.version}-src BUILDING.txt LICENSE.txt NOTICE.txt pom.xml RELEASE-NOTES.txt src jexl2-compat target/** commons-jexl-2.1.1-src/src/main/config/checkstyle.xml100644 0 0 21333 11673634325 17736 0ustar 0 0 commons-jexl-2.1.1-src/src/main/config/findbugs-exclude-filter.xml100644 0 0 3652 11673634325 22277 0ustar 0 0 commons-jexl-2.1.1-src/src/main/config/header.txt100644 0 0 1461 11673634325 17027 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/Debugger.java100644 0 0 55124 11673634324 23634 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.regex.Pattern; import org.apache.commons.jexl2.parser.ASTAdditiveNode; import org.apache.commons.jexl2.parser.ASTAdditiveOperator; import org.apache.commons.jexl2.parser.ASTAmbiguous; import org.apache.commons.jexl2.parser.ASTAndNode; import org.apache.commons.jexl2.parser.ASTArrayAccess; import org.apache.commons.jexl2.parser.ASTArrayLiteral; import org.apache.commons.jexl2.parser.ASTAssignment; import org.apache.commons.jexl2.parser.ASTBitwiseAndNode; import org.apache.commons.jexl2.parser.ASTBitwiseComplNode; import org.apache.commons.jexl2.parser.ASTBitwiseOrNode; import org.apache.commons.jexl2.parser.ASTBitwiseXorNode; import org.apache.commons.jexl2.parser.ASTBlock; import org.apache.commons.jexl2.parser.ASTConstructorNode; import org.apache.commons.jexl2.parser.ASTDivNode; import org.apache.commons.jexl2.parser.ASTEQNode; import org.apache.commons.jexl2.parser.ASTERNode; import org.apache.commons.jexl2.parser.ASTEmptyFunction; import org.apache.commons.jexl2.parser.ASTFalseNode; import org.apache.commons.jexl2.parser.ASTForeachStatement; import org.apache.commons.jexl2.parser.ASTFunctionNode; import org.apache.commons.jexl2.parser.ASTGENode; import org.apache.commons.jexl2.parser.ASTGTNode; import org.apache.commons.jexl2.parser.ASTIdentifier; import org.apache.commons.jexl2.parser.ASTIfStatement; import org.apache.commons.jexl2.parser.ASTJexlScript; import org.apache.commons.jexl2.parser.ASTLENode; import org.apache.commons.jexl2.parser.ASTLTNode; import org.apache.commons.jexl2.parser.ASTMapEntry; import org.apache.commons.jexl2.parser.ASTMapLiteral; import org.apache.commons.jexl2.parser.ASTMethodNode; import org.apache.commons.jexl2.parser.ASTModNode; import org.apache.commons.jexl2.parser.ASTMulNode; import org.apache.commons.jexl2.parser.ASTNENode; import org.apache.commons.jexl2.parser.ASTNRNode; import org.apache.commons.jexl2.parser.ASTNotNode; import org.apache.commons.jexl2.parser.ASTNullLiteral; import org.apache.commons.jexl2.parser.ASTNumberLiteral; import org.apache.commons.jexl2.parser.ASTOrNode; import org.apache.commons.jexl2.parser.ASTReference; import org.apache.commons.jexl2.parser.ASTReferenceExpression; import org.apache.commons.jexl2.parser.ASTReturnStatement; import org.apache.commons.jexl2.parser.ASTSizeFunction; import org.apache.commons.jexl2.parser.ASTSizeMethod; import org.apache.commons.jexl2.parser.ASTStringLiteral; import org.apache.commons.jexl2.parser.ASTTernaryNode; import org.apache.commons.jexl2.parser.ASTTrueNode; import org.apache.commons.jexl2.parser.ASTUnaryMinusNode; import org.apache.commons.jexl2.parser.ASTVar; import org.apache.commons.jexl2.parser.ASTWhileStatement; import org.apache.commons.jexl2.parser.JexlNode; import org.apache.commons.jexl2.parser.ParserVisitor; import org.apache.commons.jexl2.parser.SimpleNode; /** * Helps pinpoint the cause of problems in expressions that fail during evaluation. *

* It rebuilds an expression string from the tree and the start/end offsets of the cause * in that string. *

* This implies that exceptions during evaluation do allways carry the node that's causing * the error. * @since 2.0 */ final class Debugger implements ParserVisitor { /** The builder to compose messages. */ private final StringBuilder builder; /** The cause of the issue to debug. */ private JexlNode cause; /** The starting character location offset of the cause in the builder. */ private int start; /** The ending character location offset of the cause in the builder. */ private int end; /** * Creates a Debugger. */ Debugger() { builder = new StringBuilder(); cause = null; start = 0; end = 0; } /** * Seeks the location of an error cause (a node) in an expression. * @param node the node to debug * @return true if the cause was located, false otherwise */ public boolean debug(JexlNode node) { start = 0; end = 0; if (node != null) { builder.setLength(0); this.cause = node; // make arg cause become the root cause JexlNode root = node; while (root.jjtGetParent() != null) { root = root.jjtGetParent(); } root.jjtAccept(this, null); } return end > 0; } /** * @return The rebuilt expression */ public String data() { return builder.toString(); } /** * Rebuilds an expression from a Jexl node. * @param node the node to rebuilt from * @return the rebuilt expression * @since 2.1 */ public String data(JexlNode node) { start = 0; end = 0; if (node != null) { builder.setLength(0); this.cause = node; node.jjtAccept(this, null); } return builder.toString(); } /** * @return The starting offset location of the cause in the expression */ public int start() { return start; } /** * @return The end offset location of the cause in the expression */ public int end() { return end; } /** * Checks if a child node is the cause to debug & adds its representation * to the rebuilt expression. * @param node the child node * @param data visitor pattern argument * @return visitor pattern value */ private Object accept(JexlNode node, Object data) { if (node == cause) { start = builder.length(); } Object value = node.jjtAccept(this, data); if (node == cause) { end = builder.length(); } return value; } /** * Adds a statement node to the rebuilt expression. * @param child the child node * @param data visitor pattern argument * @return visitor pattern value */ private Object acceptStatement(JexlNode child, Object data) { Object value = accept(child, data); // blocks, if, for & while dont need a ';' at end if (child instanceof ASTBlock || child instanceof ASTIfStatement || child instanceof ASTForeachStatement || child instanceof ASTWhileStatement) { return value; } builder.append(";"); return value; } /** * Checks if a terminal node is the the cause to debug & adds its * representation to the rebuilt expression. * @param node the child node * @param image the child node token image (may be null) * @param data visitor pattern argument * @return visitor pattern value */ private Object check(JexlNode node, String image, Object data) { if (node == cause) { start = builder.length(); } if (image != null) { builder.append(image); } else { builder.append(node.toString()); } if (node == cause) { end = builder.length(); } return data; } /** * Checks if the children of a node using infix notation is the cause to debug, * adds their representation to the rebuilt expression. * @param node the child node * @param infix the child node token * @param paren whether the child should be parenthesized * @param data visitor pattern argument * @return visitor pattern value */ private Object infixChildren(JexlNode node, String infix, boolean paren, Object data) { int num = node.jjtGetNumChildren(); //child.jjtGetNumChildren() > 1; if (paren) { builder.append("("); } for (int i = 0; i < num; ++i) { if (i > 0) { builder.append(infix); } accept(node.jjtGetChild(i), data); } if (paren) { builder.append(")"); } return data; } /** * Checks if the child of a node using prefix notation is the cause to debug, * adds their representation to the rebuilt expression. * @param node the node * @param prefix the node token * @param data visitor pattern argument * @return visitor pattern value */ private Object prefixChild(JexlNode node, String prefix, Object data) { boolean paren = node.jjtGetChild(0).jjtGetNumChildren() > 1; builder.append(prefix); if (paren) { builder.append("("); } accept(node.jjtGetChild(0), data); if (paren) { builder.append(")"); } return data; } /** {@inheritDoc} */ public Object visit(ASTAdditiveNode node, Object data) { // need parenthesis if not in operator precedence order boolean paren = node.jjtGetParent() instanceof ASTMulNode || node.jjtGetParent() instanceof ASTDivNode || node.jjtGetParent() instanceof ASTModNode; int num = node.jjtGetNumChildren(); //child.jjtGetNumChildren() > 1; if (paren) { builder.append("("); } accept(node.jjtGetChild(0), data); for (int i = 1; i < num; ++i) { accept(node.jjtGetChild(i), data); } if (paren) { builder.append(")"); } return data; } /** {@inheritDoc} */ public Object visit(ASTAdditiveOperator node, Object data) { builder.append(' '); builder.append(node.image); builder.append(' '); return data; } /** {@inheritDoc} */ public Object visit(ASTAndNode node, Object data) { return infixChildren(node, " && ", false, data); } /** {@inheritDoc} */ public Object visit(ASTArrayAccess node, Object data) { accept(node.jjtGetChild(0), data); int num = node.jjtGetNumChildren(); for (int i = 1; i < num; ++i) { builder.append("["); accept(node.jjtGetChild(i), data); builder.append("]"); } return data; } /** {@inheritDoc} */ public Object visit(ASTArrayLiteral node, Object data) { int num = node.jjtGetNumChildren(); builder.append("[ "); if (num > 0) { accept(node.jjtGetChild(0), data); for (int i = 1; i < num; ++i) { builder.append(", "); accept(node.jjtGetChild(i), data); } } builder.append(" ]"); return data; } /** {@inheritDoc} */ public Object visit(ASTAssignment node, Object data) { return infixChildren(node, " = ", false, data); } /** {@inheritDoc} */ public Object visit(ASTBitwiseAndNode node, Object data) { return infixChildren(node, " & ", false, data); } /** {@inheritDoc} */ public Object visit(ASTBitwiseComplNode node, Object data) { return prefixChild(node, "~", data); } /** {@inheritDoc} */ public Object visit(ASTBitwiseOrNode node, Object data) { boolean paren = node.jjtGetParent() instanceof ASTBitwiseAndNode; return infixChildren(node, " | ", paren, data); } /** {@inheritDoc} */ public Object visit(ASTBitwiseXorNode node, Object data) { boolean paren = node.jjtGetParent() instanceof ASTBitwiseAndNode; return infixChildren(node, " ^ ", paren, data); } /** {@inheritDoc} */ public Object visit(ASTBlock node, Object data) { builder.append("{ "); int num = node.jjtGetNumChildren(); for (int i = 0; i < num; ++i) { JexlNode child = node.jjtGetChild(i); acceptStatement(child, data); } builder.append(" }"); return data; } /** {@inheritDoc} */ public Object visit(ASTDivNode node, Object data) { return infixChildren(node, " / ", false, data); } /** {@inheritDoc} */ public Object visit(ASTEmptyFunction node, Object data) { builder.append("empty("); accept(node.jjtGetChild(0), data); builder.append(")"); return data; } /** {@inheritDoc} */ public Object visit(ASTEQNode node, Object data) { return infixChildren(node, " == ", false, data); } /** {@inheritDoc} */ public Object visit(ASTERNode node, Object data) { return infixChildren(node, " =~ ", false, data); } /** {@inheritDoc} */ public Object visit(ASTFalseNode node, Object data) { return check(node, "false", data); } /** {@inheritDoc} */ public Object visit(ASTForeachStatement node, Object data) { builder.append("for("); accept(node.jjtGetChild(0), data); builder.append(" : "); accept(node.jjtGetChild(1), data); builder.append(") "); if (node.jjtGetNumChildren() > 2) { acceptStatement(node.jjtGetChild(2), data); } else { builder.append(';'); } return data; } /** {@inheritDoc} */ public Object visit(ASTGENode node, Object data) { return infixChildren(node, " >= ", false, data); } /** {@inheritDoc} */ public Object visit(ASTGTNode node, Object data) { return infixChildren(node, " > ", false, data); } /** Checks identifiers that contain space, quote, double-quotes or backspace. */ private static final Pattern QUOTED_IDENTIFIER = Pattern.compile("['\"\\s\\\\]"); /** {@inheritDoc} */ public Object visit(ASTIdentifier node, Object data) { String image = node.image; if (QUOTED_IDENTIFIER.matcher(image).find()) { // quote it image = "'" + node.image.replace("'", "\\'") + "'"; } return check(node, image, data); } /** {@inheritDoc} */ public Object visit(ASTIfStatement node, Object data) { builder.append("if ("); accept(node.jjtGetChild(0), data); builder.append(") "); if (node.jjtGetNumChildren() > 1) { acceptStatement(node.jjtGetChild(1), data); if (node.jjtGetNumChildren() > 2) { builder.append(" else "); acceptStatement(node.jjtGetChild(2), data); } else { builder.append(';'); } } else { builder.append(';'); } return data; } /** {@inheritDoc} */ public Object visit(ASTNumberLiteral node, Object data) { return check(node, node.image, data); } /** {@inheritDoc} */ public Object visit(ASTJexlScript node, Object data) { int num = node.jjtGetNumChildren(); for (int i = 0; i < num; ++i) { JexlNode child = node.jjtGetChild(i); acceptStatement(child, data); } return data; } /** {@inheritDoc} */ public Object visit(ASTLENode node, Object data) { return infixChildren(node, " <= ", false, data); } /** {@inheritDoc} */ public Object visit(ASTLTNode node, Object data) { return infixChildren(node, " < ", false, data); } /** {@inheritDoc} */ public Object visit(ASTMapEntry node, Object data) { accept(node.jjtGetChild(0), data); builder.append(" : "); accept(node.jjtGetChild(1), data); return data; } /** {@inheritDoc} */ public Object visit(ASTMapLiteral node, Object data) { int num = node.jjtGetNumChildren(); builder.append("{ "); if (num > 0) { accept(node.jjtGetChild(0), data); for (int i = 1; i < num; ++i) { builder.append(", "); accept(node.jjtGetChild(i), data); } } else { builder.append(':'); } builder.append(" }"); return data; } /** {@inheritDoc} */ public Object visit(ASTConstructorNode node, Object data) { int num = node.jjtGetNumChildren(); builder.append("new "); builder.append("("); accept(node.jjtGetChild(0), data); for (int i = 1; i < num; ++i) { builder.append(", "); accept(node.jjtGetChild(i), data); } builder.append(")"); return data; } /** {@inheritDoc} */ public Object visit(ASTFunctionNode node, Object data) { int num = node.jjtGetNumChildren(); accept(node.jjtGetChild(0), data); builder.append(":"); accept(node.jjtGetChild(1), data); builder.append("("); for (int i = 2; i < num; ++i) { if (i > 2) { builder.append(", "); } accept(node.jjtGetChild(i), data); } builder.append(")"); return data; } /** {@inheritDoc} */ public Object visit(ASTMethodNode node, Object data) { int num = node.jjtGetNumChildren(); accept(node.jjtGetChild(0), data); builder.append("("); for (int i = 1; i < num; ++i) { if (i > 1) { builder.append(", "); } accept(node.jjtGetChild(i), data); } builder.append(")"); return data; } /** {@inheritDoc} */ public Object visit(ASTModNode node, Object data) { return infixChildren(node, " % ", false, data); } /** {@inheritDoc} */ public Object visit(ASTMulNode node, Object data) { return infixChildren(node, " * ", false, data); } /** {@inheritDoc} */ public Object visit(ASTNENode node, Object data) { return infixChildren(node, " != ", false, data); } /** {@inheritDoc} */ public Object visit(ASTNRNode node, Object data) { return infixChildren(node, " !~ ", false, data); } /** {@inheritDoc} */ public Object visit(ASTNotNode node, Object data) { builder.append("!"); accept(node.jjtGetChild(0), data); return data; } /** {@inheritDoc} */ public Object visit(ASTNullLiteral node, Object data) { check(node, "null", data); return data; } /** {@inheritDoc} */ public Object visit(ASTOrNode node, Object data) { // need parenthesis if not in operator precedence order boolean paren = node.jjtGetParent() instanceof ASTAndNode; return infixChildren(node, " || ", paren, data); } /** {@inheritDoc} */ public Object visit(ASTReference node, Object data) { int num = node.jjtGetNumChildren(); accept(node.jjtGetChild(0), data); for (int i = 1; i < num; ++i) { builder.append("."); accept(node.jjtGetChild(i), data); } return data; } /** {@inheritDoc} */ public Object visit(ASTReferenceExpression node, Object data) { JexlNode first = node.jjtGetChild(0); builder.append('('); accept(first, data); builder.append(')'); int num = node.jjtGetNumChildren(); for (int i = 1; i < num; ++i) { builder.append("["); accept(node.jjtGetChild(i), data); builder.append("]"); } return data; } /** {@inheritDoc} */ public Object visit(ASTReturnStatement node, Object data) { builder.append("return "); accept(node.jjtGetChild(0), data); return data; } /** {@inheritDoc} */ public Object visit(ASTSizeFunction node, Object data) { builder.append("size("); accept(node.jjtGetChild(0), data); builder.append(")"); return data; } /** {@inheritDoc} */ public Object visit(ASTSizeMethod node, Object data) { check(node, "size()", data); return data; } /** {@inheritDoc} */ public Object visit(ASTStringLiteral node, Object data) { String img = node.image.replace("'", "\\'"); return check(node, "'" + img + "'", data); } /** {@inheritDoc} */ public Object visit(ASTTernaryNode node, Object data) { accept(node.jjtGetChild(0), data); if (node.jjtGetNumChildren() > 2) { builder.append("? "); accept(node.jjtGetChild(1), data); builder.append(" : "); accept(node.jjtGetChild(2), data); } else { builder.append("?:"); accept(node.jjtGetChild(1), data); } return data; } /** {@inheritDoc} */ public Object visit(ASTTrueNode node, Object data) { check(node, "true", data); return data; } /** {@inheritDoc} */ public Object visit(ASTUnaryMinusNode node, Object data) { return prefixChild(node, "-", data); } /** {@inheritDoc} */ public Object visit(ASTVar node, Object data) { builder.append("var "); check(node, node.image, data); return data; } /** {@inheritDoc} */ public Object visit(ASTWhileStatement node, Object data) { builder.append("while ("); accept(node.jjtGetChild(0), data); builder.append(") "); if (node.jjtGetNumChildren() > 1) { acceptStatement(node.jjtGetChild(1), data); } else { builder.append(';'); } return data; } /** {@inheritDoc} */ public Object visit(SimpleNode node, Object data) { throw new UnsupportedOperationException("unexpected type of node"); } /** {@inheritDoc} */ public Object visit(ASTAmbiguous node, Object data) { throw new UnsupportedOperationException("unexpected type of node"); } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/DebugInfo.java100644 0 0 5015 11673634322 23722 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Helper class to carry in info such as a url/file name, line and column for * debugging information reporting. */ public class DebugInfo implements JexlInfo { /** line number. */ private final int line; /** column number. */ private final int column; /** name. */ private final String name; /** * Create info. * @param tn template name * @param l line number * @param c column */ public DebugInfo(String tn, int l, int c) { name = tn; line = l; column = c; } /** * Formats this info in the form 'name@line:column'. * @return the formatted info */ @Override public String toString() { StringBuilder sb = new StringBuilder(name != null? name : ""); if (line > 0) { sb.append("@"); sb.append(line); if (column > 0) { sb.append(":"); sb.append(column); } } return sb.toString(); } /** {@inheritDoc} */ public String debugString() { return toString(); } /** {@inheritDoc} * @since 2.1 */ public DebugInfo debugInfo() { return this; } /** * Gets the file/script/url name. * @return template name */ public String getName() { return name; } /** * Gets the line number. * @return line number. */ public int getLine() { return line; } /** * Gets the column number. * @return the column. */ public int getColumn() { return column; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/Expression.java100644 0 0 3521 11673634322 24217 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Represents a single JEXL expression. *

* This simple interface provides access to the underlying expression through * {@link Expression#getExpression()}. *

* *

* An expression is different than a script - it is simply a reference of * an expression. *

* * @since 1.0 */ public interface Expression { /** * Evaluates the expression with the variables contained in the * supplied {@link JexlContext}. * * @param context A JexlContext containing variables. * @return The result of this evaluation * @throws JexlException on any error */ Object evaluate(JexlContext context); /** * Returns the JEXL expression this Expression was created with. * * @return The JEXL expression to be evaluated */ String getExpression(); /** * Returns the JEXL expression by reconstructing it from the parsed tree. * @return the JEXL expression */ String dump(); } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/ExpressionImpl.java100644 0 0 11631 11673634324 25064 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; import org.apache.commons.jexl2.parser.ASTJexlScript; /** * Instances of ExpressionImpl are created by the {@link JexlEngine}, * and this is the default implementation of the {@link Expression} and * {@link Script} interface. * @since 1.0 */ public class ExpressionImpl implements Expression, Script { /** The engine for this expression. */ protected final JexlEngine jexl; /** * Original expression stripped from leading & trailing spaces. */ protected final String expression; /** * The resulting AST we can interpret. */ protected final ASTJexlScript script; /** * Do not let this be generally instantiated with a 'new'. * * @param engine the interpreter to evaluate the expression * @param expr the expression. * @param ref the parsed expression. */ protected ExpressionImpl(JexlEngine engine, String expr, ASTJexlScript ref) { jexl = engine; expression = expr; script = ref; } /** * {@inheritDoc} */ public Object evaluate(JexlContext context) { if (script.jjtGetNumChildren() < 1) { return null; } Interpreter interpreter = jexl.createInterpreter(context); interpreter.setFrame(script.createFrame((Object[]) null)); return interpreter.interpret(script.jjtGetChild(0)); } /** * {@inheritDoc} */ public String dump() { Debugger debug = new Debugger(); boolean d = debug.debug(script); return debug.data() + (d ? " /*" + debug.start() + ":" + debug.end() + "*/" : "/*?:?*/ "); } /** * {@inheritDoc} */ public String getExpression() { return expression; } /** * Provide a string representation of this expression. * @return the expression or blank if it's null. */ @Override public String toString() { String expr = getExpression(); return expr == null ? "" : expr; } /** * {@inheritDoc} */ public String getText() { return toString(); } /** * {@inheritDoc} */ public Object execute(JexlContext context) { Interpreter interpreter = jexl.createInterpreter(context); interpreter.setFrame(script.createFrame((Object[]) null)); return interpreter.interpret(script); } /** * {@inheritDoc} * @since 2.1 */ public Object execute(JexlContext context, Object... args) { Interpreter interpreter = jexl.createInterpreter(context); interpreter.setFrame(script.createFrame(args)); return interpreter.interpret(script); } /** * {@inheritDoc} * @since 2.1 */ public String[] getParameters() { return script.getParameters(); } /** * {@inheritDoc} * @since 2.1 */ public String[] getLocalVariables() { return script.getLocalVariables(); } /** * {@inheritDoc} * @since 2.1 */ public Set> getVariables() { return jexl.getVariables(this); } /** * {@inheritDoc} * @since 2.1 */ public Callable callable(JexlContext context) { return callable(context, (Object[]) null); } /** * {@inheritDoc} * @since 2.1 */ public Callable callable(JexlContext context, Object... args) { final Interpreter interpreter = jexl.createInterpreter(context); interpreter.setFrame(script.createFrame(args)); return new Callable() { /** Use interpreter as marker for not having run. */ private Object result = interpreter; public Object call() throws Exception { if (result == interpreter) { result = interpreter.interpret(script); } return result; } }; } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/AbstractExecutor.java100644 0 0 31425 11673634325 27205 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import org.apache.commons.jexl2.internal.introspection.MethodKey; import org.apache.commons.jexl2.introspection.JexlMethod; import org.apache.commons.jexl2.introspection.JexlPropertySet; import org.apache.commons.jexl2.introspection.JexlPropertyGet; import java.lang.reflect.InvocationTargetException; /** * Abstract class that is used to execute an arbitrary * method that is introspected. This is the superclass * for all other AbstractExecutor classes. * * @since 1.0 */ public abstract class AbstractExecutor { /** A marker for invocation failures in tryInvoke. */ public static final Object TRY_FAILED = new Object() { @Override public String toString() { return "tryExecute failed"; } }; /** * A helper to initialize the marker methods (array.get, list.get, etc...). * @param clazz the class to introspect * @param name the name of the method * @param parms the parameters * @return the method */ static java.lang.reflect.Method initMarker(Class clazz, String name, Class... parms) { try { return clazz.getMethod(name, parms); } catch (Exception xnever) { throw new Error(xnever); } } /** * Creates an arguments array. * @param args the list of arguments * @return the arguments array */ static Object[] makeArgs(Object... args) { return args; } /** The class this executor applies to. */ protected final Class objectClass; /** Method to be executed. */ protected final java.lang.reflect.Method method; /** * Default and sole constructor. * @param theClass the class this executor applies to * @param theMethod the method held by this executor */ protected AbstractExecutor(Class theClass, java.lang.reflect.Method theMethod) { objectClass = theClass; method = theMethod; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { return this == obj || (obj instanceof AbstractExecutor && equals((AbstractExecutor) obj)); } /** {@inheritDoc} */ @Override public int hashCode() { return method.hashCode(); } /** * Indicates whether some other executor is equivalent to this one. * @param arg the other executor to check * @return true if both executors are equivalent, false otherwise */ public boolean equals(AbstractExecutor arg) { // common equality check if (!this.getClass().equals(arg.getClass())) { return false; } if (!this.getMethod().equals(arg.getMethod())) { return false; } if (!this.getTargetClass().equals(arg.getTargetClass())) { return false; } // specific equality check Object lhsp = this.getTargetProperty(); Object rhsp = arg.getTargetProperty(); if (lhsp == null && rhsp == null) { return true; } if (lhsp != null && rhsp != null) { return lhsp.equals(rhsp); } return false; } /** * Tell whether the executor is alive by looking * at the value of the method. * * @return boolean Whether the executor is alive. */ public final boolean isAlive() { return (method != null); } /** * Specifies if this executor is cacheable and able to be reused for this * class of object it was returned for. * * @return true if can be reused for this class, false if not */ public boolean isCacheable() { return method != null; } /** * Gets the method to be executed or used as a marker. * @return Method The method used by execute in derived classes. */ public final java.lang.reflect.Method getMethod() { return method; } /** * Gets the object class targeted by this executor. * @return the target object class */ public final Class getTargetClass() { return objectClass; } /** * Gets the property targeted by this executor. * @return the target property */ public Object getTargetProperty() { return null; } /** * Gets the method name used. * @return method name */ public final String getMethodName() { return method.getName(); } /** * Checks whether a tryExecute failed or not. * @param exec the value returned by tryExecute * @return true if tryExecute failed, false otherwise */ public final boolean tryFailed(Object exec) { return exec == TRY_FAILED; } /** * Abstract class that is used to execute an arbitrary 'get' method. */ public abstract static class Get extends AbstractExecutor implements JexlPropertyGet { /** * Default and sole constructor. * @param theClass the class this executor applies to * @param theMethod the method held by this executor */ protected Get(Class theClass, java.lang.reflect.Method theMethod) { super(theClass, theMethod); } /** {@inheritDoc} */ public final Object invoke(Object obj) throws Exception { return execute(obj); } /** {@inheritDoc} */ public final Object tryInvoke(Object obj, Object key) { return tryExecute(obj, key); } /** * Gets the property value from an object. * * @param obj The object to get the property from. * @return The property value. * @throws IllegalAccessException Method is inaccessible. * @throws InvocationTargetException Method body throws an exception. */ public abstract Object execute(Object obj) throws IllegalAccessException, InvocationTargetException; /** * Tries to reuse this executor, checking that it is compatible with * the actual set of arguments. *

Compatibility means that: * o must be of the same class as this executor's * target class and * property must be of the same class as this * executor's target property (for list and map based executors) and have the same * value (for other types).

* @param obj The object to get the property from. * @param key The property to get from the object. * @return The property value or TRY_FAILED if checking failed. */ public Object tryExecute(Object obj, Object key) { return TRY_FAILED; } } /** * Abstract class that is used to execute an arbitrary 'set' method. */ public abstract static class Set extends AbstractExecutor implements JexlPropertySet { /** * Default and sole constructor. * @param theClass the class this executor applies to * @param theMethod the method held by this executor */ protected Set(Class theClass, java.lang.reflect.Method theMethod) { super(theClass, theMethod); } /** {@inheritDoc} */ public final Object invoke(Object obj, Object arg) throws Exception { return execute(obj, arg); } /** {@inheritDoc} */ public final Object tryInvoke(Object obj, Object key, Object value) { return tryExecute(obj, key, value); } /** * Sets the property value of an object. * * @param obj The object to set the property in. * @param value The value. * @return The return value. * @throws IllegalAccessException Method is inaccessible. * @throws InvocationTargetException Method body throws an exception. */ public abstract Object execute(Object obj, Object value) throws IllegalAccessException, InvocationTargetException; /** * Tries to reuse this executor, checking that it is compatible with * the actual set of arguments. *

Compatibility means that: * o must be of the same class as this executor's * target class, * property must be of the same class as this * executor's target property (for list and map based executors) and have the same * value (for other types) * and that arg must be a valid argument for this * executor underlying method.

* @param obj The object to invoke the method from. * @param key The property to set in the object. * @param value The value to use as the property value. * @return The return value or TRY_FAILED if checking failed. */ public Object tryExecute(Object obj, Object key, Object value) { return TRY_FAILED; } } /** * Abstract class that is used to execute an arbitrary method. */ public abstract static class Method extends AbstractExecutor implements JexlMethod { /** * A helper class to pass the method & parameters. */ protected static final class Parameter { /** The method. */ private final java.lang.reflect.Method method; /** The method key. */ private final MethodKey key; /** Creates an instance. * @param m the method * @param k the method key */ public Parameter(java.lang.reflect.Method m, MethodKey k) { method = m; key = k; } } /** The method key discovered from the arguments. */ protected final MethodKey key; /** * Creates a new instance. * @param c the class this executor applies to * @param km the method and MethodKey to encapsulate. */ protected Method(Class c, Parameter km) { super(c, km.method); key = km.key; } /** {@inheritDoc} */ public final Object invoke(Object obj, Object[] params) throws Exception { return execute(obj, params); } /** {@inheritDoc} */ public final Object tryInvoke(String name, Object obj, Object[] params) { return tryExecute(name, obj, params); } /** {@inheritDoc} */ @Override public Object getTargetProperty() { return key; } /** * Returns the return type of the method invoked. * @return return type */ public final Class getReturnType() { return method.getReturnType(); } /** * Invokes the method to be executed. * * @param obj the object to invoke the method upon * @param args the method arguments * @return the result of the method invocation * @throws IllegalAccessException Method is inaccessible. * @throws InvocationTargetException Method body throws an exception. */ public abstract Object execute(Object obj, Object[] args) throws IllegalAccessException, InvocationTargetException; /** * Tries to reuse this executor, checking that it is compatible with * the actual set of arguments. * @param obj the object to invoke the method upon * @param name the method name * @param args the method arguments * @return the result of the method invocation or TRY_FAILED if checking failed. */ public Object tryExecute(String name, Object obj, Object[] args){ return TRY_FAILED; } } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/ArrayIterator.java100644 0 0 5730 11673634325 26473 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.util.Iterator; import java.util.NoSuchElementException; import java.lang.reflect.Array; /** *

* An Iterator wrapper for an Object[]. This will * allow us to deal with all array like structures * in a consistent manner. *

*

* WARNING : this class's operations are NOT synchronized. * It is meant to be used in a single thread, newly created * for each use in the #foreach() directive. * If this is used or shared, synchronize in the * next() method. *

* * @since 1.0 */ public class ArrayIterator implements Iterator { /** The objects to iterate over. */ private final Object array; /** The size of the array. */ private final int size; /** The current position and size in the array. */ private int pos; /** * Creates a new iterator instance for the specified array. * @param arr The array for which an iterator is desired. */ public ArrayIterator(Object arr) { if (arr == null) { array = null; pos = 0; size = 0; } else if (!arr.getClass().isArray()) { throw new IllegalArgumentException(arr.getClass() + " is not an array"); } else { array = arr; pos = 0; size = Array.getLength(array); } } /** * Move to next element in the array. * * @return The next object in the array. */ public Object next() { if (pos < size) { return Array.get(array, pos++); } // we screwed up... throw new NoSuchElementException("No more elements: " + pos + " / " + size); } /** * Check to see if there is another element in the array. * * @return Whether there is another element. */ public boolean hasNext() { return (pos < size); } /** * No op--merely added to satify the Iterator interface. */ public void remove() { throw new UnsupportedOperationException(); } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/ArrayListWrapper.java100644 0 0 12615 11673634324 27175 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.lang.reflect.Array; import java.util.AbstractList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; /** * A class that wraps an array within an AbstractList. *

* It overrides all methods because introspection uses this class a a marker for wrapped arrays; the declared class * for any method is thus always ArrayListWrapper. *

*/ public class ArrayListWrapper extends AbstractList { /** the array to wrap. */ private final Object array; /** * Create the wrapper. * @param anArray {@link #array} */ public ArrayListWrapper(Object anArray) { if (!anArray.getClass().isArray()) { throw new IllegalArgumentException(anArray.getClass() + " is not an array"); } this.array = anArray; } /** {@inheritDoc} */ @Override public Object get(int index) { return Array.get(array, index); } /** {@inheritDoc} */ @Override public Object set(int index, Object element) { Object old = get(index); Array.set(array, index, element); return old; } /** {@inheritDoc} */ @Override public int size() { return Array.getLength(array); } @Override public Object[] toArray() { final int size = size(); Object[] a = new Object[size]; for(int i = 0; i < size; ++i) { a[i] = get(i); } return a; } @Override @SuppressWarnings("unchecked") public T[] toArray(T[] a) { int size = size(); if (a.length < size) { T[] x = (T[]) Array.newInstance(a.getClass().getComponentType(), size); System.arraycopy(a, a.length, x, 0, a.length); } for(int i = 0; i < size; ++i) { a[i] = (T) get(i); } if (a.length > size) { a[size] = null; } return a; } @Override public int indexOf(Object o) { final int size = size(); if (o == null) { for (int i = 0; i < size; i++) { if (get(i) == null) { return i; } } } else { for (int i = 0; i < size; i++) { if (o.equals(get(i))) { return i; } } } return -1; } @Override public boolean contains(Object o) { return indexOf(o) != -1; } @Override public boolean isEmpty() { return super.isEmpty(); } @Override public Iterator iterator() { return super.iterator(); } @Override public boolean containsAll(Collection c) { return super.containsAll(c); } @Override public int lastIndexOf(Object o) { return super.lastIndexOf(o); } @Override public ListIterator listIterator() { return super.listIterator(); } @Override public ListIterator listIterator(int index) { return super.listIterator(index); } @Override public List subList(int fromIndex, int toIndex) { return super.subList(fromIndex, toIndex); } @Override public boolean add(Object o) { throw new UnsupportedOperationException("Not supported."); } @Override public boolean remove(Object o) { throw new UnsupportedOperationException("Not supported."); } @Override public boolean addAll(Collection c) { throw new UnsupportedOperationException("Not supported."); } @Override public boolean addAll(int index, Collection c) { throw new UnsupportedOperationException("Not supported."); } @Override public boolean removeAll(Collection c) { throw new UnsupportedOperationException("Not supported."); } @Override public boolean retainAll(Collection c) { throw new UnsupportedOperationException("Not supported."); } @Override public void clear() { throw new UnsupportedOperationException("Not supported."); } @Override public void add(int index, Object element) { throw new UnsupportedOperationException("Not supported."); } @Override public Object remove(int index) { throw new UnsupportedOperationException("Not supported."); } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/BooleanGetExecutor.java100644 0 0 6110 11673634325 27432 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.lang.reflect.InvocationTargetException; /** * Specialized executor to get a boolean property from an object. * @since 2.0 */ public final class BooleanGetExecutor extends AbstractExecutor.Get { /** The property. */ private final String property; /** * Creates an instance by attempting discovery of the get method. * @param is the introspector * @param clazz the class to introspect * @param key the property to get */ public BooleanGetExecutor(Introspector is, Class clazz, String key) { super(clazz, discover(is, clazz, key)); property = key; } /** {@inheritDoc} */ @Override public Object getTargetProperty() { return property; } /** {@inheritDoc} */ @Override public Object execute(Object obj) throws IllegalAccessException, InvocationTargetException { return method == null ? null : method.invoke(obj, (Object[]) null); } /** {@inheritDoc} */ @Override public Object tryExecute(Object obj, Object key) { if (obj != null && method != null // ensure method name matches the property name && property.equals(key) && objectClass.equals(obj.getClass())) { try { return method.invoke(obj, (Object[]) null); } catch (InvocationTargetException xinvoke) { return TRY_FAILED; // fail } catch (IllegalAccessException xill) { return TRY_FAILED;// fail } } return TRY_FAILED; } /** * Discovers the method for a {@link BooleanGet}. *

The method to be found should be named "is{P,p}property and return a boolean.

*@param is the introspector *@param clazz the class to find the get method from *@param property the the property name *@return the method if found, null otherwise */ static java.lang.reflect.Method discover(Introspector is, final Class clazz, String property) { java.lang.reflect.Method m = PropertyGetExecutor.discoverGet(is, "is", clazz, property); return (m != null && m.getReturnType() == Boolean.TYPE) ? m : null; } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/DuckGetExecutor.java100644 0 0 6606 11673634324 26752 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.lang.reflect.InvocationTargetException; /** * Specialized executor to get a property from an object. *

Duck as in duck-typing for an interface like: * * interface Get { * Object get(Object key); * } * *

* @since 2.0 */ public final class DuckGetExecutor extends AbstractExecutor.Get { /** The property. */ private final Object property; /** * Creates an instance by attempting discovery of the get method. * @param is the introspector * @param clazz the class to introspect * @param identifier the property to get */ public DuckGetExecutor(Introspector is, Class clazz, Object identifier) { super(clazz, discover(is, clazz, identifier)); property = identifier; } /** {@inheritDoc} */ @Override public Object getTargetProperty() { return property; } /** * Get the property from the object. * @param obj the object. * @return object.get(property) * @throws IllegalAccessException Method is inaccessible. * @throws InvocationTargetException Method body throws an exception. */ @Override public Object execute(Object obj) throws IllegalAccessException, InvocationTargetException { Object[] args = {property}; return method == null ? null : method.invoke(obj, args); } /** {@inheritDoc} */ @Override public Object tryExecute(Object obj, Object key) { if (obj != null && method != null // ensure method name matches the property name && property.equals(key) && objectClass.equals(obj.getClass())) { try { Object[] args = {property}; return method.invoke(obj, args); } catch (InvocationTargetException xinvoke) { return TRY_FAILED; // fail } catch (IllegalAccessException xill) { return TRY_FAILED;// fail } } return TRY_FAILED; } /** * Discovers a method for a {@link GetExecutor.DuckGet}. *@param is the introspector *@param clazz the class to find the get method from *@param identifier the key to use as an argument to the get method *@return the method if found, null otherwise */ private static java.lang.reflect.Method discover(Introspector is, final Class clazz, Object identifier) { return is.getMethod(clazz, "get", makeArgs(identifier)); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/DuckSetExecutor.java100644 0 0 6611 11673634325 26763 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.lang.reflect.InvocationTargetException; /** * Specialized executor to set a property of an object. *

Duck as in duck-typing for an interface like: * * interface Set { * Object set(Object property, Object value); * } * *

* @since 2.0 */ public final class DuckSetExecutor extends AbstractExecutor.Set { /** The property. */ private final Object property; /** * Creates an instance. *@param is the introspector *@param clazz the class to find the set method from *@param key the key to use as 1st argument to the set method *@param value the value to use as 2nd argument to the set method */ public DuckSetExecutor(Introspector is, Class clazz, Object key, Object value) { super(clazz, discover(is, clazz, key, value)); property = key; } /** {@inheritDoc} */ @Override public Object getTargetProperty() { return property; } /** {@inheritDoc} */ @Override public Object execute(Object obj, Object value) throws IllegalAccessException, InvocationTargetException { Object[] pargs = {property, value}; if (method != null) { method.invoke(obj, pargs); } return value; } /** {@inheritDoc} */ @Override public Object tryExecute(Object obj, Object key, Object value) { if (obj != null && method != null // ensure method name matches the property name && property.equals(key) && objectClass.equals(obj.getClass())) { try { Object[] args = {property, value}; method.invoke(obj, args); return value; } catch (InvocationTargetException xinvoke) { return TRY_FAILED; // fail } catch (IllegalAccessException xill) { return TRY_FAILED;// fail } } return TRY_FAILED; } /** * Discovers the method for a {@link DuckSet}. *@param is the introspector *@param clazz the class to find the set method from *@param key the key to use as 1st argument to the set method *@param value the value to use as 2nd argument to the set method *@return the method if found, null otherwise */ private static java.lang.reflect.Method discover(Introspector is, Class clazz, Object key, Object value) { return is.getMethod(clazz, "set", makeArgs(key, value)); } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/EnumerationIterator.java100644 0 0 3765 11673634324 27710 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.util.Iterator; import java.util.Enumeration; /** * An Iterator wrapper for an Enumeration. * @param the type of object this iterator returns * @since 1.0 */ public class EnumerationIterator implements Iterator { /** * The enumeration to iterate over. */ private final Enumeration enumeration; /** * Creates a new iteratorwrapper instance for the specified * Enumeration. * * @param enumer The Enumeration to wrap. */ public EnumerationIterator(Enumeration enumer) { enumeration = enumer; } /** * Move to next element in the array. * * @return The next object in the array. */ public T next() { return enumeration.nextElement(); } /** * Check to see if there is another element in the array. * * @return Whether there is another element. */ public boolean hasNext() { return enumeration.hasMoreElements(); } /** * Unimplemented. No analogy in Enumeration */ public void remove() { // not implemented } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/introspection/ClassMap.java100644 0 0 33746 11673634325 30336 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal.introspection; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; /** * A cache of introspection information for a specific class instance. * Keys objects by an agregation of the method name and the classes * that make up the parameters. *

* Originally taken from the Velocity tree so we can be self-sufficient. *

* @see MethodKey * @since 1.0 */ final class ClassMap { /** cache of methods. */ private final MethodCache methodCache; /** cache of fields. */ private final Map fieldCache; /** * Standard constructor. * * @param aClass the class to deconstruct. * @param log the logger. */ ClassMap(Class aClass, Log log) { // eagerly cache methods methodCache = createMethodCache(aClass, log); // eagerly cache public fields fieldCache = createFieldCache(aClass); } /** * Find a Field using its name. *

The clazz parameter must be this ClassMap key.

* @param clazz the class to introspect * @param fname the field name * @return A Field object representing the field to invoke or null. */ Field findField(final Class clazz, final String fname) { return fieldCache.get(fname); } /** * Gets the field names cached by this map. * @return the array of field names */ String[] getFieldNames() { return fieldCache.keySet().toArray(new String[fieldCache.size()]); } /** * Creates a map of all public fields of a given class. * @param clazz the class to introspect * @return the map of fields (may be the empty map, can not be null) */ private static Map createFieldCache(Class clazz) { Field[] fields = clazz.getFields(); if (fields.length > 0) { Map cache = new HashMap(); for (Field field : fields) { cache.put(field.getName(), field); } return cache; } else { return Collections.emptyMap(); } } /** * Gets the methods names cached by this map. * @return the array of method names */ String[] getMethodNames() { return methodCache.names(); } /** * Gets all the methods with a given name from this map. * @param methodName the seeked methods name * @return the array of methods */ Method[] get(final String methodName) { return methodCache.get(methodName); } /** * Find a Method using the method name and parameter objects. * * @param key the method key * @return A Method object representing the method to invoke or null. * @throws MethodKey.AmbiguousException When more than one method is a match for the parameters. */ Method findMethod(final MethodKey key) throws MethodKey.AmbiguousException { return methodCache.get(key); } /** * Populate the Map of direct hits. These are taken from all the public methods * that our class, its parents and their implemented interfaces provide. * @param classToReflect the class to cache * @param log the Log * @return a newly allocated & filled up cache */ private static MethodCache createMethodCache(Class classToReflect, Log log) { // // Build a list of all elements in the class hierarchy. This one is bottom-first (i.e. we start // with the actual declaring class and its interfaces and then move up (superclass etc.) until we // hit java.lang.Object. That is important because it will give us the methods of the declaring class // which might in turn be abstract further up the tree. // // We also ignore all SecurityExceptions that might happen due to SecurityManager restrictions (prominently // hit with Tomcat 5.5). // // We can also omit all that complicated getPublic, getAccessible and upcast logic that the class map had up // until Velocity 1.4. As we always reflect all elements of the tree (that's what we have a cache for), we will // hit the public elements sooner or later because we reflect all the public elements anyway. // // Ah, the miracles of Java for(;;) ... MethodCache cache = new MethodCache(); for (; classToReflect != null; classToReflect = classToReflect.getSuperclass()) { if (Modifier.isPublic(classToReflect.getModifiers())) { populateMethodCacheWith(cache, classToReflect, log); } Class[] interfaces = classToReflect.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { populateMethodCacheWithInterface(cache, interfaces[i], log); } } return cache; } /** * Recurses up interface hierarchy to get all super interfaces. * @param cache the cache to fill * @param iface the interface to populate the cache from * @param log the Log */ private static void populateMethodCacheWithInterface(MethodCache cache, Class iface, Log log) { if (Modifier.isPublic(iface.getModifiers())) { populateMethodCacheWith(cache, iface, log); } Class[] supers = iface.getInterfaces(); for (int i = 0; i < supers.length; i++) { populateMethodCacheWithInterface(cache, supers[i], log); } } /** * Recurses up class hierarchy to get all super classes. * @param cache the cache to fill * @param clazz the class to populate the cache from * @param log the Log */ private static void populateMethodCacheWith(MethodCache cache, Class clazz, Log log) { try { Method[] methods = clazz.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { int modifiers = methods[i].getModifiers(); if (Modifier.isPublic(modifiers)) { cache.put(methods[i]); } } } catch (SecurityException se) { // Everybody feels better with... if (log.isDebugEnabled()) { log.debug("While accessing methods of " + clazz + ": ", se); } } } /** * This is the cache to store and look up the method information. *

* It stores the association between: * - a key made of a method name & an array of argument types. * - a method. *

*

* Since the invocation of the associated method is dynamic, there is no need (nor way) to differentiate between * foo(int,int) & foo(Integer,Integer) since in practise, only the latter form will be used through a call. * This of course, applies to all 8 primitive types. *

*/ static final class MethodCache { /** * A method that returns itself used as a marker for cache miss, * allows the underlying cache map to be strongly typed. * @return itself as a method */ public static Method cacheMiss() { try { return MethodCache.class.getMethod("cacheMiss"); } catch (Exception xio) { // this really cant make an error... return null; } } /** The cache miss marker method. */ private static final Method CACHE_MISS = cacheMiss(); /** The initial size of the primitive conversion map. */ private static final int PRIMITIVE_SIZE = 13; /** The primitive type to class conversion map. */ private static final Map, Class> PRIMITIVE_TYPES; static { PRIMITIVE_TYPES = new HashMap, Class>(PRIMITIVE_SIZE); PRIMITIVE_TYPES.put(Boolean.TYPE, Boolean.class); PRIMITIVE_TYPES.put(Byte.TYPE, Byte.class); PRIMITIVE_TYPES.put(Character.TYPE, Character.class); PRIMITIVE_TYPES.put(Double.TYPE, Double.class); PRIMITIVE_TYPES.put(Float.TYPE, Float.class); PRIMITIVE_TYPES.put(Integer.TYPE, Integer.class); PRIMITIVE_TYPES.put(Long.TYPE, Long.class); PRIMITIVE_TYPES.put(Short.TYPE, Short.class); } /** Converts a primitive type to its corresponding class. *

* If the argument type is primitive then we want to convert our * primitive type signature to the corresponding Object type so * introspection for methods with primitive types will work * correctly. *

* @param parm a may-be primitive type class * @return the equivalent object class */ static Class primitiveClass(Class parm) { // it is marginally faster to get from the map than call isPrimitive... //if (!parm.isPrimitive()) return parm; Class prim = PRIMITIVE_TYPES.get(parm); return prim == null ? parm : prim; } /** * The method cache. *

* Cache of Methods, or CACHE_MISS, keyed by method * name and actual arguments used to find it. *

*/ private final Map methods = new HashMap(); /** * Map of methods that are searchable according to method parameters to find a match. */ private final MethodMap methodMap = new MethodMap(); /** * Find a Method using the method name and parameter objects. *

* Look in the methodMap for an entry. If found, * it'll either be a CACHE_MISS, in which case we * simply give up, or it'll be a Method, in which * case, we return it. *

*

* If nothing is found, then we must actually go * and introspect the method from the MethodMap. *

* @param methodKey the method key * @return A Method object representing the method to invoke or null. * @throws MethodKey.AmbiguousException When more than one method is a match for the parameters. */ Method get(final MethodKey methodKey) throws MethodKey.AmbiguousException { synchronized (methodMap) { Method cacheEntry = methods.get(methodKey); // We looked this up before and failed. if (cacheEntry == CACHE_MISS) { return null; } if (cacheEntry == null) { try { // That one is expensive... cacheEntry = methodMap.find(methodKey); if (cacheEntry != null) { methods.put(methodKey, cacheEntry); } else { methods.put(methodKey, CACHE_MISS); } } catch (MethodKey.AmbiguousException ae) { // that's a miss :-) methods.put(methodKey, CACHE_MISS); throw ae; } } // Yes, this might just be null. return cacheEntry; } } /** * Adds a method to the map. * @param method the method to add */ void put(Method method) { synchronized (methodMap) { MethodKey methodKey = new MethodKey(method); // We don't overwrite methods. Especially not if we fill the // cache from defined class towards java.lang.Object because // abstract methods in superclasses would else overwrite concrete // classes further down the hierarchy. if (methods.get(methodKey) == null) { methods.put(methodKey, method); methodMap.add(method); } } } /** * Gets all the method names from this map. * @return the array of method name */ String[] names() { synchronized (methodMap) { return methodMap.names(); } } /** * Gets all the methods with a given name from this map. * @param methodName the seeked methods name * @return the array of methods (null or non-empty) */ Method[] get(final String methodName) { synchronized (methodMap) { List lm = methodMap.get(methodName); if (lm != null && !lm.isEmpty()) { return lm.toArray(new Method[lm.size()]); } else { return null; } } } } }././@LongLink100644 0 0 153 11673650055 10262 Lustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/introspection/IntrospectorBase.javacommons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/introspection/IntrospectorBas100644 0 0 30242 11673634325 31020 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal.introspection; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.Map; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.apache.commons.logging.Log; /** * This basic function of this class is to return a Method object for a * particular class given the name of a method and the parameters to the method * in the form of an Object[] *

* The first time the Introspector sees a class it creates a class method map * for the class in question. Basically the class method map is a Hastable where * Method objects are keyed by a concatenation of the method name and the names * of classes that make up the parameters. * * For example, a method with the following signature: * * public void method(String a, StringBuffer b) * * would be mapped by the key: * * "method" + "java.lang.String" + "java.lang.StringBuffer" * * This mapping is performed for all the methods in a class and stored. * @since 1.0 */ public class IntrospectorBase { /** the logger. */ protected final Log rlog; /** * Holds the method maps for the classes we know about, keyed by Class. */ private final Map, ClassMap> classMethodMaps = new HashMap, ClassMap>(); /** * The class loader used to solve constructors if needed. */ private ClassLoader loader; /** * Holds the map of classes ctors we know about as well as unknown ones. */ private final Map> constructorsMap = new HashMap>(); /** * Holds the set of classes we have introspected. */ private final Map> constructibleClasses = new HashMap>(); /** * Create the introspector. * @param log the logger to use */ public IntrospectorBase(Log log) { this.rlog = log; loader = getClass().getClassLoader(); } /** * Gets a class by name through this introspector class loader. * @param className the class name * @return the class instance or null if it could not be found */ public Class getClassByName(String className) { try { return Class.forName(className, false, loader); } catch (ClassNotFoundException xignore) { return null; } } /** * Gets the method defined by the MethodKey for the class c. * * @param c Class in which the method search is taking place * @param key Key of the method being searched for * @return The desired method object * @throws MethodKey.AmbiguousException if no unambiguous method could be found through introspection */ public Method getMethod(Class c, MethodKey key) { try { ClassMap classMap = getMap(c); return classMap.findMethod(key); } catch (MethodKey.AmbiguousException xambiguous) { // whoops. Ambiguous. Make a nice log message and return null... if (rlog != null && rlog.isInfoEnabled()) { rlog.info("ambiguous method invocation: " + c.getName() + "." + key.debugString(), xambiguous); } return null; } } /** * Gets the field named by key for the class c. * * @param c Class in which the field search is taking place * @param key Name of the field being searched for * @return the desired field or null if it does not exist or is not accessible * */ public Field getField(Class c, String key) { ClassMap classMap = getMap(c); return classMap.findField(c, key); } /** * Gets the array of accessible field names known for a given class. * @param c the class * @return the class field names */ public String[] getFieldNames(Class c) { if (c == null) { return new String[0]; } ClassMap classMap = getMap(c); return classMap.getFieldNames(); } /** * Gets the array of accessible methods names known for a given class. * @param c the class * @return the class method names */ public String[] getMethodNames(Class c) { if (c == null) { return new String[0]; } ClassMap classMap = getMap(c); return classMap.getMethodNames(); } /** * Gets the array of accessible method known for a given class. * @param c the class * @param methodName the method name * @return the array of methods (null or not empty) */ public Method[] getMethods(Class c, String methodName) { if (c == null) { return null; } ClassMap classMap = getMap(c); return classMap.get(methodName); } /** * A Constructor get cache-miss. */ private static class CacheMiss { /** The constructor used as cache-miss. */ @SuppressWarnings("unused") public CacheMiss() {} } /** The cache-miss marker for the constructors map. */ private static final Constructor CTOR_MISS = CacheMiss.class.getConstructors()[0]; /** * Sets the class loader used to solve constructors. *

Also cleans the constructors and methods caches.

* @param cloader the class loader; if null, use this instance class loader */ public void setLoader(ClassLoader cloader) { ClassLoader previous = loader; if (cloader == null) { cloader = getClass().getClassLoader(); } if (!cloader.equals(loader)) { // clean up constructor and class maps synchronized (constructorsMap) { Iterator>> entries = constructorsMap.entrySet().iterator(); while (entries.hasNext()) { Map.Entry> entry = entries.next(); Class clazz = entry.getValue().getDeclaringClass(); if (isLoadedBy(previous, clazz)) { entries.remove(); // the method name is the name of the class constructibleClasses.remove(entry.getKey().getMethod()); } } } // clean up method maps synchronized (classMethodMaps) { Iterator, ClassMap>> entries = classMethodMaps.entrySet().iterator(); while (entries.hasNext()) { Map.Entry, ClassMap> entry = entries.next(); Class clazz = entry.getKey(); if (isLoadedBy(previous, clazz)) { entries.remove(); } } } loader = cloader; } } /** * Checks whether a class is loaded through a given class loader or one of its ascendants. * @param loader the class loader * @param clazz the class to check * @return true if clazz was loaded through the loader, false otherwise */ private static boolean isLoadedBy(ClassLoader loader, Class clazz) { if (loader != null) { ClassLoader cloader = clazz.getClassLoader(); while (cloader != null) { if (cloader.equals(loader)) { return true; } else { cloader = cloader.getParent(); } } } return false; } /** * Gets the constructor defined by the MethodKey. * * @param key Key of the constructor being searched for * @return The desired constructor object * or null if no unambiguous constructor could be found through introspection. */ public Constructor getConstructor(final MethodKey key) { return getConstructor(null, key); } /** * Gets the constructor defined by the MethodKey. * @param c the class we want to instantiate * @param key Key of the constructor being searched for * @return The desired constructor object * or null if no unambiguous constructor could be found through introspection. */ public Constructor getConstructor(final Class c, final MethodKey key) { Constructor ctor = null; synchronized (constructorsMap) { ctor = constructorsMap.get(key); // that's a clear miss if (CTOR_MISS.equals(ctor)) { return null; } // let's introspect... if (ctor == null) { final String cname = key.getMethod(); // do we know about this class? Class clazz = constructibleClasses.get(cname); try { // do find the most specific ctor if (clazz == null) { if (c != null && c.getName().equals(key.getMethod())) { clazz = c; } else { clazz = loader.loadClass(cname); } // add it to list of known loaded classes constructibleClasses.put(cname, clazz); } List> l = new LinkedList>(); for (Constructor ictor : clazz.getConstructors()) { l.add(ictor); } // try to find one ctor = key.getMostSpecificConstructor(l); if (ctor != null) { constructorsMap.put(key, ctor); } else { constructorsMap.put(key, CTOR_MISS); } } catch (ClassNotFoundException xnotfound) { if (rlog != null && rlog.isInfoEnabled()) { rlog.info("unable to find class: " + cname + "." + key.debugString(), xnotfound); } ctor = null; } catch (MethodKey.AmbiguousException xambiguous) { if (rlog != null && rlog.isInfoEnabled()) { rlog.info("ambiguous constructor invocation: " + cname + "." + key.debugString(), xambiguous); } ctor = null; } } return ctor; } } /** * Gets the ClassMap for a given class. * @param c the class * @return the class map */ private ClassMap getMap(Class c) { synchronized (classMethodMaps) { ClassMap classMap = classMethodMaps.get(c); if (classMap == null) { classMap = new ClassMap(c, rlog); classMethodMaps.put(c, classMap); } return classMap; } } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/introspection/MethodKey.java100644 0 0 63147 11673634325 30522 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal.introspection; import java.util.List; import java.util.LinkedList; import java.util.Iterator; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Arrays; /** * A method key usable by the introspector cache. *

* This stores a method (or class) name and parameters. *

*

* This replaces the original key scheme which used to build the key * by concatenating the method name and parameters class names as one string * with the exception that primitive types were converted to their object class equivalents. *

*

* The key is still based on the same information, it is just wrapped in an object instead. * Primitive type classes are converted to they object equivalent to make a key; * int foo(int) and int foo(Integer) do generate the same key. *

* A key can be constructed either from arguments (array of objects) or from parameters * (array of class). * Roughly 3x faster than string key to access the map & uses less memory. */ public final class MethodKey { /** The hash code. */ private final int hashCode; /** The method name. */ private final String method; /** The parameters. */ private final Class[] params; /** A marker for empty parameter list. */ private static final Class[] NOARGS = new Class[0]; /** The hash code constants. */ private static final int HASH = 37; /** * Creates a key from a method name and a set of arguments. * @param aMethod the method to generate the key from * @param args the intended method arguments */ public MethodKey(String aMethod, Object[] args) { super(); // !! keep this in sync with the other ctor (hash code) !! this.method = aMethod; int hash = this.method.hashCode(); final int size; // CSOFF: InnerAssignment if (args != null && (size = args.length) > 0) { this.params = new Class[size]; for (int p = 0; p < size; ++p) { Object arg = args[p]; // null arguments use void as Void.class as marker Class parm = arg == null ? Void.class : arg.getClass(); hash = (HASH * hash) + parm.hashCode(); this.params[p] = parm; } } else { this.params = NOARGS; } this.hashCode = hash; } /** * Creates a key from a method. * @param aMethod the method to generate the key from. */ MethodKey(Method aMethod) { this(aMethod.getName(), aMethod.getParameterTypes()); } /** * Creates a key from a method name and a set of parameters. * @param aMethod the method to generate the key from * @param args the intended method parameters */ MethodKey(String aMethod, Class[] args) { super(); // !! keep this in sync with the other ctor (hash code) !! this.method = aMethod.intern(); int hash = this.method.hashCode(); final int size; // CSOFF: InnerAssignment if (args != null && (size = args.length) > 0) { this.params = new Class[size]; for (int p = 0; p < size; ++p) { Class parm = ClassMap.MethodCache.primitiveClass(args[p]); hash = (HASH * hash) + parm.hashCode(); this.params[p] = parm; } } else { this.params = NOARGS; } this.hashCode = hash; } /** * Gets this key's method name. * @return the method name */ String getMethod() { return method; } /** * Gets this key's method parameter classes. * @return the parameters */ Class[] getParameters() { return params; } /** {@inheritDoc} */ @Override public int hashCode() { return hashCode; } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (obj instanceof MethodKey) { MethodKey key = (MethodKey) obj; return method.equals(key.method) && Arrays.equals(params, key.params); } return false; } /** {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(method); for (Class c : params) { builder.append(c == Void.class ? "null" : c.getName()); } return builder.toString(); } /** * Outputs a human readable debug representation of this key. * @return method(p0, p1, ...) */ public String debugString() { StringBuilder builder = new StringBuilder(method); builder.append('('); for (int i = 0; i < params.length; i++) { if (i > 0) { builder.append(", "); } builder.append(Void.class == params[i] ? "null" : params[i].getName()); } builder.append(')'); return builder.toString(); } /** * Gets the most specific method that is applicable to the parameters of this key. * @param methods a list of methods. * @return the most specific method. * @throws MethodKey.AmbiguousException if there is more than one. */ public Method getMostSpecificMethod(List methods) { return METHODS.getMostSpecific(methods, params); } /** * Gets the most specific constructor that is applicable to the parameters of this key. * @param methods a list of constructors. * @return the most specific constructor. * @throws MethodKey.AmbiguousException if there is more than one. */ public Constructor getMostSpecificConstructor(List> methods) { return CONSTRUCTORS.getMostSpecific(methods, params); } /** * Determines whether a type represented by a class object is * convertible to another type represented by a class object using a * method invocation conversion, treating object types of primitive * types as if they were primitive types (that is, a Boolean actual * parameter type matches boolean primitive formal type). This behavior * is because this method is used to determine applicable methods for * an actual parameter list, and primitive types are represented by * their object duals in reflective method calls. * * @param formal the formal parameter type to which the actual * parameter type should be convertible * @param actual the actual parameter type. * @param possibleVarArg whether or not we're dealing with the last parameter * in the method declaration * @return true if either formal type is assignable from actual type, * or formal is a primitive type and actual is its corresponding object * type or an object type of a primitive type that can be converted to * the formal type. */ public static boolean isInvocationConvertible(Class formal, Class actual, boolean possibleVarArg) { /* if it's a null, it means the arg was null */ if (actual == null && !formal.isPrimitive()) { return true; } /* Check for identity or widening reference conversion */ if (actual != null && formal.isAssignableFrom(actual)) { return true; } /* Check for boxing with widening primitive conversion. Note that * actual parameters are never primitives. */ if (formal.isPrimitive()) { if (formal == Boolean.TYPE && actual == Boolean.class) { return true; } if (formal == Character.TYPE && actual == Character.class) { return true; } if (formal == Byte.TYPE && actual == Byte.class) { return true; } if (formal == Short.TYPE && (actual == Short.class || actual == Byte.class)) { return true; } if (formal == Integer.TYPE && (actual == Integer.class || actual == Short.class || actual == Byte.class)) { return true; } if (formal == Long.TYPE && (actual == Long.class || actual == Integer.class || actual == Short.class || actual == Byte.class)) { return true; } if (formal == Float.TYPE && (actual == Float.class || actual == Long.class || actual == Integer.class || actual == Short.class || actual == Byte.class)) { return true; } if (formal == Double.TYPE && (actual == Double.class || actual == Float.class || actual == Long.class || actual == Integer.class || actual == Short.class || actual == Byte.class)) { return true; } } /* Check for vararg conversion. */ if (possibleVarArg && formal.isArray()) { if (actual != null && actual.isArray()) { actual = actual.getComponentType(); } return isInvocationConvertible(formal.getComponentType(), actual, false); } return false; } /** * Determines whether a type represented by a class object is * convertible to another type represented by a class object using a * method invocation conversion, without matching object and primitive * types. This method is used to determine the more specific type when * comparing signatures of methods. * * @param formal the formal parameter type to which the actual * parameter type should be convertible * @param actual the actual parameter type. * @param possibleVarArg whether or not we're dealing with the last parameter * in the method declaration * @return true if either formal type is assignable from actual type, * or formal and actual are both primitive types and actual can be * subject to widening conversion to formal. */ public static boolean isStrictInvocationConvertible(Class formal, Class actual, boolean possibleVarArg) { /* we shouldn't get a null into, but if so */ if (actual == null && !formal.isPrimitive()) { return true; } /* Check for identity or widening reference conversion */ if (formal.isAssignableFrom(actual)) { return true; } /* Check for widening primitive conversion. */ if (formal.isPrimitive()) { if (formal == Short.TYPE && (actual == Byte.TYPE)) { return true; } if (formal == Integer.TYPE && (actual == Short.TYPE || actual == Byte.TYPE)) { return true; } if (formal == Long.TYPE && (actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) { return true; } if (formal == Float.TYPE && (actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) { return true; } if (formal == Double.TYPE && (actual == Float.TYPE || actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) { return true; } } /* Check for vararg conversion. */ if (possibleVarArg && formal.isArray()) { if (actual != null && actual.isArray()) { actual = actual.getComponentType(); } return isStrictInvocationConvertible(formal.getComponentType(), actual, false); } return false; } /** * whether a method/ctor is more specific than a previously compared one. */ private static final int MORE_SPECIFIC = 0; /** * whether a method/ctor is less specific than a previously compared one. */ private static final int LESS_SPECIFIC = 1; /** * A method/ctor doesn't match a previously compared one. */ private static final int INCOMPARABLE = 2; /** * Simple distinguishable exception, used when * we run across ambiguous overloading. Caught * by the introspector. */ public static class AmbiguousException extends RuntimeException { /** * Version Id for serializable. */ private static final long serialVersionUID = -2314636505414551664L; } /** * Utility for parameters matching. * @param Method or Constructor */ private abstract static class Parameters { /** * Extract the parameter types from its applicable argument. * @param app a method or constructor * @return the parameters */ protected abstract Class[] getParameterTypes(T app); // CSOFF: RedundantThrows /** * Gets the most specific method that is applicable to actual argument types. * @param methods a list of methods. * @param classes list of argument types. * @return the most specific method. * @throws MethodKey.AmbiguousException if there is more than one. */ private T getMostSpecific(List methods, Class[] classes) { LinkedList applicables = getApplicables(methods, classes); if (applicables.isEmpty()) { return null; } if (applicables.size() == 1) { return applicables.getFirst(); } /* * This list will contain the maximally specific methods. Hopefully at * the end of the below loop, the list will contain exactly one method, * (the most specific method) otherwise we have ambiguity. */ LinkedList maximals = new LinkedList(); for (Iterator applicable = applicables.iterator(); applicable.hasNext();) { T app = applicable.next(); Class[] appArgs = getParameterTypes(app); boolean lessSpecific = false; for (Iterator maximal = maximals.iterator(); !lessSpecific && maximal.hasNext();) { T max = maximal.next(); // CSOFF: MissingSwitchDefault switch (moreSpecific(appArgs, getParameterTypes(max))) { case MORE_SPECIFIC: /* * This method is more specific than the previously * known maximally specific, so remove the old maximum. */ maximal.remove(); break; case LESS_SPECIFIC: /* * This method is less specific than some of the * currently known maximally specific methods, so we * won't add it into the set of maximally specific * methods */ lessSpecific = true; break; } } // CSON: MissingSwitchDefault if (!lessSpecific) { maximals.addLast(app); } } if (maximals.size() > 1) { // We have more than one maximally specific method throw new AmbiguousException(); } return maximals.getFirst(); } // CSON: RedundantThrows /** * Determines which method signature (represented by a class array) is more * specific. This defines a partial ordering on the method signatures. * * @param c1 first signature to compare * @param c2 second signature to compare * @return MORE_SPECIFIC if c1 is more specific than c2, LESS_SPECIFIC if * c1 is less specific than c2, INCOMPARABLE if they are incomparable. */ private int moreSpecific(Class[] c1, Class[] c2) { boolean c1MoreSpecific = false; boolean c2MoreSpecific = false; // compare lengths to handle comparisons where the size of the arrays // doesn't match, but the methods are both applicable due to the fact // that one is a varargs method if (c1.length > c2.length) { return MORE_SPECIFIC; } if (c2.length > c1.length) { return LESS_SPECIFIC; } // ok, move on and compare those of equal lengths for (int i = 0; i < c1.length; ++i) { if (c1[i] != c2[i]) { boolean last = (i == c1.length - 1); c1MoreSpecific = c1MoreSpecific || isStrictConvertible(c2[i], c1[i], last); c2MoreSpecific = c2MoreSpecific || isStrictConvertible(c1[i], c2[i], last); } } if (c1MoreSpecific) { if (c2MoreSpecific) { // Incomparable due to cross-assignable arguments (i.e. foo(String, Object) vs. foo(Object, String)) return INCOMPARABLE; } return MORE_SPECIFIC; } if (c2MoreSpecific) { return LESS_SPECIFIC; } // attempt to choose by picking the one with the greater number of primitives or latest primitive parameter int primDiff = 0; for (int c = 0; c < c1.length; ++c) { if (c1[c].isPrimitive()) { primDiff += 1 << c; } if (c2[c].isPrimitive()) { primDiff -= 1 << c; } } if (primDiff > 0) { return MORE_SPECIFIC; } else if (primDiff < 0) { return LESS_SPECIFIC; } /* * Incomparable due to non-related arguments (i.e. * foo(Runnable) vs. foo(Serializable)) */ return INCOMPARABLE; } /** * Returns all methods that are applicable to actual argument types. * * @param methods list of all candidate methods * @param classes the actual types of the arguments * @return a list that contains only applicable methods (number of * formal and actual arguments matches, and argument types are assignable * to formal types through a method invocation conversion). */ private LinkedList getApplicables(List methods, Class[] classes) { LinkedList list = new LinkedList(); for (Iterator imethod = methods.iterator(); imethod.hasNext();) { T method = imethod.next(); if (isApplicable(method, classes)) { list.add(method); } } return list; } /** * Returns true if the supplied method is applicable to actual * argument types. * * @param method method that will be called * @param classes arguments to method * @return true if method is applicable to arguments */ private boolean isApplicable(T method, Class[] classes) { Class[] methodArgs = getParameterTypes(method); // if samee number or args or // there's just one more methodArg than class arg // and the last methodArg is an array, then treat it as a vararg if (methodArgs.length == classes.length || methodArgs.length == classes.length + 1 && methodArgs[methodArgs.length - 1].isArray()) { // this will properly match when the last methodArg // is an array/varargs and the last class is the type of array // (e.g. String when the method is expecting String...) for (int i = 0; i < classes.length; ++i) { if (!isConvertible(methodArgs[i], classes[i], false)) { // if we're on the last arg and the method expects an array if (i == classes.length - 1 && methodArgs[i].isArray()) { // check to see if the last arg is convertible // to the array's component type return isConvertible(methodArgs[i], classes[i], true); } return false; } } return true; } // more arguments given than the method accepts; check for varargs if (methodArgs.length > 0) { // check that the last methodArg is an array Class lastarg = methodArgs[methodArgs.length - 1]; if (!lastarg.isArray()) { return false; } // check that they all match up to the last method arg for (int i = 0; i < methodArgs.length - 1; ++i) { if (!isConvertible(methodArgs[i], classes[i], false)) { return false; } } // check that all remaining arguments are convertible to the vararg type Class vararg = lastarg.getComponentType(); for (int i = methodArgs.length - 1; i < classes.length; ++i) { if (!isConvertible(vararg, classes[i], false)) { return false; } } return true; } // no match return false; } /** * @see #isInvocationConvertible(Class, Class, boolean) * @param formal the formal parameter type to which the actual * parameter type should be convertible * @param actual the actual parameter type. * @param possibleVarArg whether or not we're dealing with the last parameter * in the method declaration * @return see isMethodInvocationConvertible. */ private boolean isConvertible(Class formal, Class actual, boolean possibleVarArg) { // if we see Void.class, the argument was null return isInvocationConvertible(formal, actual.equals(Void.class) ? null : actual, possibleVarArg); } /** * @see #isStrictInvocationConvertible(Class, Class, boolean) * @param formal the formal parameter type to which the actual * parameter type should be convertible * @param actual the actual parameter type. * @param possibleVarArg whether or not we're dealing with the last parameter * in the method declaration * @return see isStrictMethodInvocationConvertible. */ private boolean isStrictConvertible(Class formal, Class actual, boolean possibleVarArg) { // if we see Void.class, the argument was null return isStrictInvocationConvertible(formal, actual.equals(Void.class) ? null : actual, possibleVarArg); } } /** * The parameter matching service for methods. */ private static final Parameters METHODS = new Parameters() { @Override protected Class[] getParameterTypes(Method app) { return app.getParameterTypes(); } }; /** * The parameter matching service for constructors. */ private static final Parameters> CONSTRUCTORS = new Parameters>() { @Override protected Class[] getParameterTypes(Constructor app) { return app.getParameterTypes(); } }; } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/introspection/MethodMap.java100644 0 0 10136 11673634325 30475 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal.introspection; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A map of method names to methods. * @since 1.0 */ final class MethodMap { /** * Keep track of all methods with the same name. */ private final Map> methodByNameMap = new HashMap>(); /** * Add a method to a list of methods by name. For a particular class we are * keeping track of all the methods with the same name. * * @param method the method. */ public synchronized void add(Method method) { String methodName = method.getName(); List l = methodByNameMap.get(methodName); if (l == null) { l = new ArrayList(); methodByNameMap.put(methodName, l); } l.add(method); } /** * Return a list of methods with the same name. * * @param key the name. * @return List list of methods. */ public synchronized List get(String key) { return methodByNameMap.get(key); } /** * Returns the array of method names accessible in this class. * @return the array of names */ public synchronized String[] names() { java.util.Set set = methodByNameMap.keySet(); return set.toArray(new String[set.size()]); } /** *

* Find a method. Attempts to find the * most specific applicable method using the * algorithm described in the JLS section * 15.12.2 (with the exception that it can't * distinguish a primitive type argument from * an object type argument, since in reflection * primitive type arguments are represented by * their object counterparts, so for an argument of * type (say) java.lang.Integer, it will not be able * to decide between a method that takes int and a * method that takes java.lang.Integer as a parameter. *

* *

* This turns out to be a relatively rare case * where this is needed - however, functionality * like this is needed. *

* * @param methodName name of method * @param args the actual arguments with which the method is called * @return the most specific applicable method, or null if no * method is applicable. * @throws MethodKey.AmbiguousException if there is more than one maximally * specific applicable method */ // CSOFF: RedundantThrows public Method find(String methodName, Object[] args) throws MethodKey.AmbiguousException { return find(new MethodKey(methodName, args)); } /** * Finds a method by key. * @param methodKey the key * @return the method * @throws MethodKey.AmbiguousException if find is ambiguous */ Method find(MethodKey methodKey) throws MethodKey.AmbiguousException { List methodList = get(methodKey.getMethod()); if (methodList == null) { return null; } return methodKey.getMostSpecificMethod(methodList); } // CSON: RedundantThrows }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/introspection/package.html100644 0 0 3555 11673634325 30224 0ustar 0 0 Package Documentation for org.apache.commons.jexl2.introspection Package Provides low-level introspective services.

This internal package is not intended for public usage and there is no guarantee that its public classes or methods will remain as is in subsequent versions.

The IntrospectorBase, ClassMap, MethodKey, MethodMap form the base of the introspection service. They allow to describe classes and their methods, keeping them in a cache (@see IntrospectorBase) to speed up property getters/setters and method discovery used during expression evaluation.

The cache materialized in Introspector creates one entry per class containing a map of all accessible public methods keyed by name and signature.

commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/Introspector.java100644 0 0 26077 11673634325 26425 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.lang.ref.SoftReference; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import org.apache.commons.jexl2.internal.introspection.IntrospectorBase; import org.apache.commons.jexl2.internal.introspection.MethodKey; import org.apache.commons.logging.Log; /** * Default introspection services. *

Finding methods as well as property getters & setters.

* @since 1.0 */ public class Introspector { /** The logger to use for all warnings & errors. */ protected final Log rlog; /** The soft reference to the introspector currently in use. */ private volatile SoftReference ref; /** * Creates an introspector. * @param log the logger to use for warnings. */ protected Introspector(Log log) { rlog = log; ref = new SoftReference(null); } /** * Coerce an Object to an Integer. * @param arg the Object to coerce * @return an Integer if it can be converted, null otherwise */ protected Integer toInteger(Object arg) { if (arg == null) { return null; } if (arg instanceof Number) { return Integer.valueOf(((Number) arg).intValue()); } try { return Integer.valueOf(arg.toString()); } catch (NumberFormatException xnumber) { return null; } } /** * Coerce an Object to a String. * @param arg the Object to coerce * @return a String if it can be converted, null otherwise */ protected String toString(Object arg) { return arg == null ? null : arg.toString(); } /** * Gets the current introspector base. *

If the reference has been collected, this method will recreate the underlying introspector.

* @return the introspector */ // CSOFF: DoubleCheckedLocking protected final IntrospectorBase base() { IntrospectorBase intro = ref.get(); if (intro == null) { // double checked locking is ok (fixed by Java 5 memory model). synchronized(this) { intro = ref.get(); if (intro == null) { intro = new IntrospectorBase(rlog); ref = new SoftReference(intro); } } } return intro; } // CSON: DoubleCheckedLocking /** * Sets the underlying class loader for class solving resolution. * @param loader the loader to use */ public void setClassLoader(ClassLoader loader) { base().setLoader(loader); } /** * Gets a class by name through this introspector class loader. * @param className the class name * @return the class instance or null if it could not be found */ public Class getClassByName(String className) { return base().getClassByName(className); } /** * Gets the field named by key for the class c. * * @param c Class in which the field search is taking place * @param key Name of the field being searched for * @return a {@link java.lang.reflect.Field} or null if it does not exist or is not accessible * */ public final Field getField(Class c, String key) { return base().getField(c, key); } /** * Gets the accessible field names known for a given class. * @param c the class * @return the class field names */ public final String[] getFieldNames(Class c) { return base().getFieldNames(c); } /** * Gets the method defined by name and * params for the Class c. * * @param c Class in which the method search is taking place * @param name Name of the method being searched for * @param params An array of Objects (not Classes) that describe the * the parameters * * @return a {@link java.lang.reflect.Method} * or null if no unambiguous method could be found through introspection. */ public final Method getMethod(Class c, String name, Object[] params) { return base().getMethod(c, new MethodKey(name, params)); } /** * Gets the method defined by key and for the Class c. * * @param c Class in which the method search is taking place * @param key MethodKey of the method being searched for * * @return a {@link java.lang.reflect.Method} * or null if no unambiguous method could be found through introspection. */ public final Method getMethod(Class c, MethodKey key) { return base().getMethod(c, key); } /** * Gets the accessible methods names known for a given class. * @param c the class * @return the class method names */ public final String[] getMethodNames(Class c) { return base().getMethodNames(c); } /** * Gets all the methods with a given name from this map. * @param c the class * @param methodName the seeked methods name * @return the array of methods */ public final Method[] getMethods(Class c, final String methodName) { return base().getMethods(c, methodName); } /** * Returns a general constructor. * @param ctorHandle the object * @param args contructor arguments * @return a {@link java.lang.reflect.Constructor} * or null if no unambiguous contructor could be found through introspection. */ public final Constructor getConstructor(Object ctorHandle, Object[] args) { String className = null; Class clazz = null; if (ctorHandle instanceof Class) { clazz = (Class) ctorHandle; className = clazz.getName(); } else if (ctorHandle != null) { className = ctorHandle.toString(); } else { return null; } return base().getConstructor(clazz, new MethodKey(className, args)); } /** * Returns a general method. * @param obj the object * @param name the method name * @param args method arguments * @return a {@link AbstractExecutor.Method}. */ public final AbstractExecutor.Method getMethodExecutor(Object obj, String name, Object[] args) { AbstractExecutor.Method me = new MethodExecutor(this, obj, name, args); return me.isAlive() ? me : null; } /** * Return a property getter. * @param obj the object to base the property from. * @param identifier property name * @return a {@link AbstractExecutor.Get}. */ public final AbstractExecutor.Get getGetExecutor(Object obj, Object identifier) { final Class claz = obj.getClass(); final String property = toString(identifier); AbstractExecutor.Get executor; // first try for a getFoo() type of property (also getfoo() ) if (property != null) { executor = new PropertyGetExecutor(this, claz, property); if (executor.isAlive()) { return executor; } //} // look for boolean isFoo() //if (property != null) { executor = new BooleanGetExecutor(this, claz, property); if (executor.isAlive()) { return executor; } } // let's see if we are a map... executor = new MapGetExecutor(this, claz, identifier); if (executor.isAlive()) { return executor; } // let's see if we can convert the identifier to an int, // if obj is an array or a list, we can still do something Integer index = toInteger(identifier); if (index != null) { executor = new ListGetExecutor(this, claz, index); if (executor.isAlive()) { return executor; } } // if that didn't work, look for set("foo") executor = new DuckGetExecutor(this, claz, identifier); if (executor.isAlive()) { return executor; } // if that didn't work, look for set("foo") executor = new DuckGetExecutor(this, claz, property); if (executor.isAlive()) { return executor; } return null; } /** * Return a property setter. * @param obj the object to base the property from. * @param identifier property name (or identifier) * @param arg value to set * @return a {@link AbstractExecutor.Set}. */ public final AbstractExecutor.Set getSetExecutor(final Object obj, final Object identifier, Object arg) { final Class claz = obj.getClass(); final String property = toString(identifier); AbstractExecutor.Set executor; // first try for a setFoo() type of property (also setfoo() ) if (property != null) { executor = new PropertySetExecutor(this, claz, property, arg); if (executor.isAlive()) { return executor; } } // let's see if we are a map... executor = new MapSetExecutor(this, claz, identifier, arg); if (executor.isAlive()) { return executor; } // let's see if we can convert the identifier to an int, // if obj is an array or a list, we can still do something Integer index = toInteger(identifier); if (index != null) { executor = new ListSetExecutor(this, claz, index, arg); if (executor.isAlive()) { return executor; } } // if that didn't work, look for set(foo) executor = new DuckSetExecutor(this, claz, identifier, arg); if (executor.isAlive()) { return executor; } // if that didn't work, look for set("foo") executor = new DuckSetExecutor(this, claz, property, arg); if (executor.isAlive()) { return executor; } return null; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/ListGetExecutor.java100644 0 0 6644 11673634325 27002 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.util.List; import java.lang.reflect.Array; /** * Specialized executor to get a property from a List or array. * @since 2.0 */ public final class ListGetExecutor extends AbstractExecutor.Get { /** The java.lang.reflect.Array.get method used as an active marker in ListGet. */ private static final java.lang.reflect.Method ARRAY_GET = initMarker(Array.class, "get", Object.class, Integer.TYPE); /** The java.util.obj.get method used as an active marker in ListGet. */ private static final java.lang.reflect.Method LIST_GET = initMarker(List.class, "get", Integer.TYPE); /** The property. */ private final Integer property; /** * Creates an instance checking for the List interface or Array capability. * @param is the introspector * @param clazz the class to introspect * @param key the key to use in obj.get(key) */ public ListGetExecutor(Introspector is, Class clazz, Integer key) { super(clazz, discover(clazz)); property = key; } /** {@inheritDoc} */ @Override public Object getTargetProperty() { return property; } /** * Get the property from the obj or array. * @param obj the List/array. * @return obj.get(key) */ @Override public Object execute(final Object obj) { if (method == ARRAY_GET) { return java.lang.reflect.Array.get(obj, property.intValue()); } else { return ((List) obj).get(property.intValue()); } } /** {@inheritDoc} */ @Override public Object tryExecute(final Object obj, Object key) { if (obj != null && method != null && objectClass.equals(obj.getClass()) && key instanceof Integer) { if (method == ARRAY_GET) { return java.lang.reflect.Array.get(obj, ((Integer) key).intValue()); } else { return ((List) obj).get(((Integer) key).intValue()); } } return TRY_FAILED; } /** * Finds the method to perform the get on a obj of array. * @param clazz the class to introspect * @return a marker method, obj.get or array.get */ static java.lang.reflect.Method discover(Class clazz) { //return discoverList(false, clazz, property); if (clazz.isArray()) { return ARRAY_GET; } if (List.class.isAssignableFrom(clazz)) { return LIST_GET; } return null; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/ListSetExecutor.java100644 0 0 10163 11673634324 27024 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.util.List; import java.lang.reflect.Array; /** * Specialized executor to set a property in a List or array. * @since 2.0 */ public final class ListSetExecutor extends AbstractExecutor.Set { /** The java.lang.reflect.Array.get method used as an active marker in ListGet. */ private static final java.lang.reflect.Method ARRAY_SET = initMarker(Array.class, "set", Object.class, Integer.TYPE, Object.class); /** The java.util.obj.set method used as an active marker in ListSet. */ private static final java.lang.reflect.Method LIST_SET = initMarker(List.class, "set", Integer.TYPE, Object.class); /** The property. */ private final Integer property; /** * Creates an instance checking for the List interface or Array capability. * @param is the introspector * @param clazz the class that might implement the map interface * @param key the key to use in obj.set(key,value) * @param value the value to use in obj.set(key,value) */ public ListSetExecutor(Introspector is, Class clazz, Integer key, Object value) { super(clazz, discover(clazz)); property = key; } /** {@inheritDoc} */ @Override public Object getTargetProperty() { return property; } /** {@inheritDoc} */ @Override public Object execute(final Object obj, Object value) { if (method == ARRAY_SET) { java.lang.reflect.Array.set(obj, property.intValue(), value); } else { @SuppressWarnings("unchecked") // LSE should only be created for array or list types final List list = (List) obj; list.set(property.intValue(), value); } return value; } /** {@inheritDoc} */ @Override public Object tryExecute(final Object obj, Object key, Object value) { if (obj != null && method != null && objectClass.equals(obj.getClass()) && key instanceof Integer) { if (method == ARRAY_SET) { Array.set(obj, ((Integer) key).intValue(), value); } else { @SuppressWarnings("unchecked") // LSE should only be created for array or list types final List list = (List) obj; list.set(((Integer) key).intValue(), value); } return value; } return TRY_FAILED; } /** * Finds the method to perform 'set' on a obj of array. * @param clazz the class to introspect * @return a marker method, obj.set or array.set */ static java.lang.reflect.Method discover(Class clazz) { if (clazz.isArray()) { // we could verify if the call can be performed but it does not change // the fact we would fail... // Class formal = clazz.getComponentType(); // Class actual = value == null? Object.class : value.getClass(); // if (IntrospectionUtils.isMethodInvocationConvertible(formal, actual, false)) { return ARRAY_SET; // } } if (List.class.isAssignableFrom(clazz)) { return LIST_SET; } return null; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/MapGetExecutor.java100644 0 0 5672 11673634325 26604 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.util.Map; /** * Specialized executor to get a property from a Map. * @since 2.0 */ public final class MapGetExecutor extends AbstractExecutor.Get { /** The java.util.map.get method used as an active marker in MapGet. */ private static final java.lang.reflect.Method MAP_GET = initMarker(Map.class, "get", Object.class); /** The property. */ private final Object property; /** * Creates an instance checking for the Map interface. * @param is the introspector * @param clazz the class that might implement the map interface * @param key the key to use in map.get(key) */ public MapGetExecutor(Introspector is, Class clazz, Object key) { super(clazz, discover(clazz)); property = key; } /** {@inheritDoc} */ @Override public Object getTargetProperty() { return property; } /** * Get the property from the map. * @param obj the map. * @return map.get(property) */ @Override public Object execute(final Object obj) { @SuppressWarnings("unchecked") // ctor only allows Map instances - see discover() method final Map map = (Map) obj; return map.get(property); } /** {@inheritDoc} */ @Override public Object tryExecute(final Object obj, Object key) { if (obj != null && method != null && objectClass.equals(obj.getClass()) && (key == null || property.getClass().equals(key.getClass()))) { @SuppressWarnings("unchecked") // ctor only allows Map instances - see discover() method final Map map = (Map) obj; return map.get(key); } return TRY_FAILED; } /** * Finds the method to perform 'get' on a map. * @param clazz the class to introspect * @return a marker method, map.get */ static java.lang.reflect.Method discover(Class clazz) { return (Map.class.isAssignableFrom(clazz))? MAP_GET : null; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/MapSetExecutor.java100644 0 0 6221 11673634324 26606 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.util.Map; import java.lang.reflect.InvocationTargetException; /** * Specialized executor to set a property in a Map. * @since 2.0 */ public final class MapSetExecutor extends AbstractExecutor.Set { /** The java.util.map.put method used as an active marker in MapSet. */ private static final java.lang.reflect.Method MAP_SET = initMarker(Map.class, "put", Object.class, Object.class); /** The property. */ private final Object property; /** * Creates an instance checking for the Map interface. *@param is the introspector *@param clazz the class that might implement the map interface *@param key the key to use as argument in map.put(key,value) *@param value the value to use as argument in map.put(key,value) */ public MapSetExecutor(Introspector is, Class clazz, Object key, Object value) { super(clazz, discover(clazz)); property = key; } /** {@inheritDoc} */ @Override public Object getTargetProperty() { return property; } /** {@inheritDoc} */ @Override public Object execute(final Object obj, Object value) throws IllegalAccessException, InvocationTargetException { @SuppressWarnings("unchecked") // ctor only allows Map instances - see discover() method final Map map = ((Map) obj); map.put(property, value); return value; } /** {@inheritDoc} */ @Override public Object tryExecute(final Object obj, Object key, Object value) { if (obj != null && method != null && objectClass.equals(obj.getClass()) && (key == null || property.getClass().equals(key.getClass()))) { @SuppressWarnings("unchecked") // ctor only allows Map instances - see discover() method final Map map = ((Map) obj); map.put(key, value); return value; } return TRY_FAILED; } /** * Finds the method to perform 'set' on a map. * @param clazz the class to introspect * @return a marker method, map.get */ static java.lang.reflect.Method discover(Class clazz) { return (Map.class.isAssignableFrom(clazz))? MAP_SET : null; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/MethodExecutor.java100644 0 0 16733 11673634324 26666 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import org.apache.commons.jexl2.internal.introspection.MethodKey; /** * Specialized executor to invoke a method on an object. * @since 2.0 */ public final class MethodExecutor extends AbstractExecutor.Method { /** Whether this method handles varargs. */ private final boolean isVarArgs; /** * Creates a new instance. * @param is the introspector used to discover the method * @param obj the object to find the method in * @param name the method name * @param args the method arguments */ public MethodExecutor(Introspector is, Object obj, String name, Object[] args) { super(obj.getClass(), discover(is, obj, name, args)); isVarArgs = method != null && isVarArgMethod(method); } /** * Invokes the method to be executed. * @param o the object to invoke the method upon * @param args the method arguments * @return the result of the method invocation * @throws IllegalAccessException Method is inaccessible. * @throws InvocationTargetException Method body throws an exception. */ @Override public Object execute(Object o, Object[] args) throws IllegalAccessException, InvocationTargetException { if (isVarArgs) { Class[] formal = method.getParameterTypes(); int index = formal.length - 1; Class type = formal[index].getComponentType(); if (args.length >= index) { args = handleVarArg(type, index, args); } } if (method.getDeclaringClass() == ArrayListWrapper.class && o.getClass().isArray()) { return method.invoke(new ArrayListWrapper(o), args); } else { return method.invoke(o, args); } } /** {@inheritDoc} */ @Override public Object tryExecute(String name, Object obj, Object[] args) { MethodKey tkey = new MethodKey(name, args); // let's assume that invocation will fly if the declaring class is the // same and arguments have the same type if (objectClass.equals(obj.getClass()) && tkey.equals(key)) { try { return execute(obj, args); } catch (InvocationTargetException xinvoke) { return TRY_FAILED; // fail } catch (IllegalAccessException xill) { return TRY_FAILED;// fail } } return TRY_FAILED; } /** * Discovers a method for a {@link MethodExecutor}. *

* If the object is an array, an attempt will be made to find the * method in a List (see {@link ArrayListWrapper}) *

*

* If the object is a class, an attempt will be made to find the * method as a static method of that class. *

* @param is the introspector used to discover the method * @param obj the object to introspect * @param method the name of the method to find * @param args the method arguments * @return a filled up parameter (may contain a null method) */ private static Parameter discover(Introspector is, Object obj, String method, Object[] args) { final Class clazz = obj.getClass(); final MethodKey key = new MethodKey(method, args); java.lang.reflect.Method m = is.getMethod(clazz, key); if (m == null && clazz.isArray()) { // check for support via our array->list wrapper m = is.getMethod(ArrayListWrapper.class, key); } if (m == null && obj instanceof Class) { m = is.getMethod((Class) obj, key); } return new Parameter(m, key); } /** * Reassembles arguments if the method is a vararg method. * @param type The vararg class type (aka component type * of the expected array arg) * @param index The index of the vararg in the method declaration * (This will always be one less than the number of * expected arguments.) * @param actual The actual parameters being passed to this method * @return The actual parameters adjusted for the varargs in order * to fit the method declaration. */ protected Object[] handleVarArg(Class type, int index, Object[] actual) { final int size = actual.length - index; // if no values are being passed into the vararg, size == 0 if (size == 1) { // if one non-null value is being passed into the vararg, // and that arg is not the sole argument and not an array of the expected type, // make the last arg an array of the expected type if (actual[index] != null) { Class aclazz = actual[index].getClass(); if (!aclazz.isArray() || !aclazz.getComponentType().equals(type)) { // create a 1-length array to hold and replace the last argument Object lastActual = Array.newInstance(type, 1); Array.set(lastActual, 0, actual[index]); actual[index] = lastActual; } } // else, the vararg is null and used as is, considered as T[] } else { // if no or multiple values are being passed into the vararg, // put them in an array of the expected type Object lastActual = Array.newInstance(type, size); for (int i = 0; i < size; i++) { Array.set(lastActual, i, actual[index + i]); } // put all arguments into a new actual array of the appropriate size Object[] newActual = new Object[index + 1]; System.arraycopy(actual, 0, newActual, 0, index); newActual[index] = lastActual; // replace the old actual array actual = newActual; } return actual; } /** * Determines if a method can accept a variable number of arguments. * @param m a the method to check * @return true if method is vararg, false otherwise */ private static boolean isVarArgMethod(java.lang.reflect.Method m) { Class[] formal = m.getParameterTypes(); if (formal == null || formal.length == 0) { return false; } else { Class last = formal[formal.length - 1]; // if the last arg is an array, then // we consider this a varargs method return last.isArray(); } } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/package.html100644 0 0 3272 11673634324 25317 0ustar 0 0 Package Documentation for org.apache.commons.jexl2 Package

Provides utilities for introspection services.

This internal package is not intended for public usage and there is no guarantee that its public classes or methods will remain as is in subsequent versions.

This set of classes implement the various forms of setters and getters used by Jexl. These are specialized forms for 'pure' properties, discovering methods of the {s,g}etProperty form, for Maps, Lists and Ducks - attempting to discover a 'get' or 'set' method, making an object walk and quack.

commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/PropertyGetExecutor.java100644 0 0 10354 11673634324 27723 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.lang.reflect.InvocationTargetException; /** * Specialized executor to get a property from an object. * @since 2.0 */ public final class PropertyGetExecutor extends AbstractExecutor.Get { /** A static signature for method(). */ private static final Object[] EMPTY_PARAMS = {}; /** The property. */ private final String property; /** * Creates an instance by attempting discovery of the get method. * @param is the introspector * @param clazz the class to introspect * @param identifier the property to get */ public PropertyGetExecutor(Introspector is, Class clazz, String identifier) { super(clazz, discover(is, clazz, identifier)); property = identifier; } /** {@inheritDoc} */ @Override public Object getTargetProperty() { return property; } /** {@inheritDoc} */ @Override public Object execute(Object o) throws IllegalAccessException, InvocationTargetException { return method == null ? null : method.invoke(o, (Object[]) null); } /** {@inheritDoc} */ @Override public Object tryExecute(Object o, Object identifier) { if (o != null && method != null && property.equals(identifier) && objectClass.equals(o.getClass())) { try { return method.invoke(o, (Object[]) null); } catch (InvocationTargetException xinvoke) { return TRY_FAILED; // fail } catch (IllegalAccessException xill) { return TRY_FAILED;// fail } } return TRY_FAILED; } /** * Discovers the method for a {@link PropertyGet}. *

The method to be found should be named "get{P,p}property.

*@param is the introspector *@param clazz the class to find the get method from *@param property the property name to find *@return the method if found, null otherwise */ static java.lang.reflect.Method discover(Introspector is, final Class clazz, String property) { return discoverGet(is, "get", clazz, property); } /** * Base method for boolean & object property get. * @param is the introspector * @param which "is" or "get" for boolean or object * @param clazz The class being examined. * @param property The property being addressed. * @return The {get,is}{p,P}roperty method if one exists, null otherwise. */ static java.lang.reflect.Method discoverGet(Introspector is, String which, Class clazz, String property) { // this is gross and linear, but it keeps it straightforward. java.lang.reflect.Method method = null; final int start = which.length(); // "get" or "is" so 3 or 2 for char case switch // start with get StringBuilder sb = new StringBuilder(which); sb.append(property); // uppercase nth char char c = sb.charAt(start); sb.setCharAt(start, Character.toUpperCase(c)); method = is.getMethod(clazz, sb.toString(), EMPTY_PARAMS); //lowercase nth char if (method == null) { sb.setCharAt(start, Character.toLowerCase(c)); method = is.getMethod(clazz, sb.toString(), EMPTY_PARAMS); } return method; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/internal/PropertySetExecutor.java100644 0 0 10211 11673634324 27727 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal; import java.lang.reflect.InvocationTargetException; /** * Specialized executor to set a property in an object. * @since 2.0 */ public final class PropertySetExecutor extends AbstractExecutor.Set { /** Index of the first character of the set{p,P}roperty. */ private static final int SET_START_INDEX = 3; /** The property. */ private final String property; /** * Creates an instance by attempting discovery of the set method. * @param is the introspector * @param clazz the class to introspect * @param identifier the property to set * @param arg the value to set into the property */ public PropertySetExecutor(Introspector is, Class clazz, String identifier, Object arg) { super(clazz, discover(is, clazz, identifier, arg)); property = identifier; } /** {@inheritDoc} */ @Override public Object getTargetProperty() { return property; } /** {@inheritDoc} */ @Override public Object execute(Object o, Object arg) throws IllegalAccessException, InvocationTargetException { Object[] pargs = {arg}; if (method != null) { method.invoke(o, pargs); } return arg; } /** {@inheritDoc} */ @Override public Object tryExecute(Object o, Object identifier, Object arg) { if (o != null && method != null // ensure method name matches the property name && property.equals(identifier) // object class should be same as executor's method declaring class && objectClass.equals(o.getClass()) // we are guaranteed the method has one parameter since it is a set(x) && (arg == null || method.getParameterTypes()[0].equals(arg.getClass()))) { try { return execute(o, arg); } catch (InvocationTargetException xinvoke) { return TRY_FAILED; // fail } catch (IllegalAccessException xill) { return TRY_FAILED;// fail } } return TRY_FAILED; } /** * Discovers the method for a {@link PropertySet}. *

The method to be found should be named "set{P,p}property.

*@param is the introspector *@param clazz the class to find the get method from *@param property the name of the property to set *@param arg the value to assign to the property *@return the method if found, null otherwise */ private static java.lang.reflect.Method discover(Introspector is, final Class clazz, String property, Object arg) { // first, we introspect for the set setter method Object[] params = {arg}; StringBuilder sb = new StringBuilder("set"); sb.append(property); // uppercase nth char char c = sb.charAt(SET_START_INDEX); sb.setCharAt(SET_START_INDEX, Character.toUpperCase(c)); java.lang.reflect.Method method = is.getMethod(clazz, sb.toString(), params); // lowercase nth char if (method == null) { sb.setCharAt(SET_START_INDEX, Character.toLowerCase(c)); method = is.getMethod(clazz, sb.toString(), params); } return method; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/Interpreter.java100644 0 0 202140 11673634322 24421 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.commons.jexl2.parser.SimpleNode; import org.apache.commons.logging.Log; import org.apache.commons.jexl2.parser.ASTFloatLiteral; import org.apache.commons.jexl2.parser.ASTIntegerLiteral; import org.apache.commons.jexl2.parser.JexlNode; import org.apache.commons.jexl2.parser.ASTAdditiveNode; import org.apache.commons.jexl2.parser.ASTAdditiveOperator; import org.apache.commons.jexl2.parser.ASTAndNode; import org.apache.commons.jexl2.parser.ASTAmbiguous; import org.apache.commons.jexl2.parser.ASTArrayAccess; import org.apache.commons.jexl2.parser.ASTArrayLiteral; import org.apache.commons.jexl2.parser.ASTAssignment; import org.apache.commons.jexl2.parser.ASTBitwiseAndNode; import org.apache.commons.jexl2.parser.ASTBitwiseComplNode; import org.apache.commons.jexl2.parser.ASTBitwiseOrNode; import org.apache.commons.jexl2.parser.ASTBitwiseXorNode; import org.apache.commons.jexl2.parser.ASTBlock; import org.apache.commons.jexl2.parser.ASTConstructorNode; import org.apache.commons.jexl2.parser.ASTDivNode; import org.apache.commons.jexl2.parser.ASTEQNode; import org.apache.commons.jexl2.parser.ASTERNode; import org.apache.commons.jexl2.parser.ASTEmptyFunction; import org.apache.commons.jexl2.parser.ASTFalseNode; import org.apache.commons.jexl2.parser.ASTFunctionNode; import org.apache.commons.jexl2.parser.ASTForeachStatement; import org.apache.commons.jexl2.parser.ASTGENode; import org.apache.commons.jexl2.parser.ASTGTNode; import org.apache.commons.jexl2.parser.ASTIdentifier; import org.apache.commons.jexl2.parser.ASTIfStatement; import org.apache.commons.jexl2.parser.ASTJexlScript; import org.apache.commons.jexl2.parser.ASTLENode; import org.apache.commons.jexl2.parser.ASTLTNode; import org.apache.commons.jexl2.parser.ASTMapEntry; import org.apache.commons.jexl2.parser.ASTMapLiteral; import org.apache.commons.jexl2.parser.ASTMethodNode; import org.apache.commons.jexl2.parser.ASTModNode; import org.apache.commons.jexl2.parser.ASTMulNode; import org.apache.commons.jexl2.parser.ASTNENode; import org.apache.commons.jexl2.parser.ASTNRNode; import org.apache.commons.jexl2.parser.ASTNotNode; import org.apache.commons.jexl2.parser.ASTNullLiteral; import org.apache.commons.jexl2.parser.ASTNumberLiteral; import org.apache.commons.jexl2.parser.ASTOrNode; import org.apache.commons.jexl2.parser.ASTReference; import org.apache.commons.jexl2.parser.ASTReferenceExpression; import org.apache.commons.jexl2.parser.ASTReturnStatement; import org.apache.commons.jexl2.parser.ASTSizeFunction; import org.apache.commons.jexl2.parser.ASTSizeMethod; import org.apache.commons.jexl2.parser.ASTStringLiteral; import org.apache.commons.jexl2.parser.ASTTernaryNode; import org.apache.commons.jexl2.parser.ASTTrueNode; import org.apache.commons.jexl2.parser.ASTUnaryMinusNode; import org.apache.commons.jexl2.parser.ASTWhileStatement; import org.apache.commons.jexl2.parser.Node; import org.apache.commons.jexl2.parser.ParserVisitor; import org.apache.commons.jexl2.introspection.Uberspect; import org.apache.commons.jexl2.introspection.JexlMethod; import org.apache.commons.jexl2.introspection.JexlPropertyGet; import org.apache.commons.jexl2.introspection.JexlPropertySet; import org.apache.commons.jexl2.parser.ASTVar; /** * An interpreter of JEXL syntax. * * @since 2.0 */ public class Interpreter implements ParserVisitor { /** The logger. */ protected final Log logger; /** The uberspect. */ protected final Uberspect uberspect; /** The arithmetic handler. */ protected final JexlArithmetic arithmetic; /** The map of registered functions. */ protected final Map functions; /** The map of registered functions. */ protected Map functors; /** The context to store/retrieve variables. */ protected final JexlContext context; /** Strict interpreter flag. Do not modify; will be made final/private in a later version. */ protected boolean strict; /** Silent intepreter flag. Do not modify; will be made final/private in a later version. */ protected boolean silent; /** Cache executors. */ protected final boolean cache; /** Registers or arguments. */ protected Object[] registers = null; /** * Parameter names if any. * Intended for use in debugging; not currently used externally. * @since 2.1 */ @SuppressWarnings("unused") private String[] parameters = null; /** * Cancellation support. * @see #isCancelled() * @since 2.1 */ private volatile boolean cancelled = false; /** Empty parameters for method matching. */ protected static final Object[] EMPTY_PARAMS = new Object[0]; /** * Creates an interpreter. * @param jexl the engine creating this interpreter * @param aContext the context to evaluate expression * @deprecated */ @Deprecated public Interpreter(JexlEngine jexl, JexlContext aContext) { this(jexl, aContext, !jexl.isLenient(), jexl.isSilent()); } /** * Creates an interpreter. * @param jexl the engine creating this interpreter * @param aContext the context to evaluate expression * @param strictFlag whether this interpreter runs in strict mode * @param silentFlag whether this interpreter runs in silent mode * @since 2.1 */ public Interpreter(JexlEngine jexl, JexlContext aContext, boolean strictFlag, boolean silentFlag) { this.logger = jexl.logger; this.uberspect = jexl.uberspect; this.arithmetic = jexl.arithmetic; this.functions = jexl.functions; this.strict = strictFlag; this.silent = silentFlag; this.cache = jexl.cache != null; this.context = aContext != null? aContext : JexlEngine.EMPTY_CONTEXT; this.functors = null; } /** * Copy constructor. * @param base the base to copy * @since 2.1 */ protected Interpreter(Interpreter base) { this.logger = base.logger; this.uberspect = base.uberspect; this.arithmetic = base.arithmetic; this.functions = base.functions; this.strict = base.strict; this.silent = base.silent; this.cache = base.cache; this.context = base.context; this.functors = base.functors; } /** * Sets whether this interpreter considers unknown variables, methods and constructors as errors. * @param flag true for strict, false for lenient * @deprecated Do not use; will be removed in a later version * @since 2.1 */ // TODO why add a method and then deprecate it? @Deprecated public void setStrict(boolean flag) { this.strict = flag; } /** * Sets whether this interpreter throws JexlException when encountering errors. * @param flag true for silent, false for verbose * @deprecated Do not use; will be removed in a later version */ @Deprecated public void setSilent(boolean flag) { this.silent = flag; } /** * Checks whether this interpreter considers unknown variables, methods and constructors as errors. * @return true if strict, false otherwise * @since 2.1 */ public boolean isStrict() { return this.strict; } /** * Checks whether this interpreter throws JexlException when encountering errors. * @return true if silent, false otherwise */ public boolean isSilent() { return this.silent; } /** * Interpret the given script/expression. *

* If the underlying JEXL engine is silent, errors will be logged through its logger as info. *

* @param node the script or expression to interpret. * @return the result of the interpretation. * @throws JexlException if any error occurs during interpretation. */ public Object interpret(JexlNode node) { try { return node.jjtAccept(this, null); } catch (JexlException.Return xreturn) { Object value = xreturn.getValue(); return value; } catch (JexlException xjexl) { if (silent) { logger.warn(xjexl.getMessage(), xjexl.getCause()); return null; } throw xjexl; } finally { functors = null; parameters = null; registers = null; } } /** * Gets the context. * @return the {@link JexlContext} used for evaluation. * @since 2.1 */ protected JexlContext getContext() { return context; } /** * Gets the uberspect. * @return an {@link Uberspect} */ protected Uberspect getUberspect() { return uberspect; } /** * Sets this interpreter registers for bean access/assign expressions. *

Use setFrame(...) instead.

* @param theRegisters the array of registers */ @Deprecated protected void setRegisters(Object... theRegisters) { if (theRegisters != null) { String[] regStrs = new String[theRegisters.length]; for (int r = 0; r < regStrs.length; ++r) { regStrs[r] = "#" + r; } this.parameters = regStrs; } this.registers = theRegisters; } /** * Sets this interpreter parameters and arguments. * @param frame the calling frame * @since 2.1 */ protected void setFrame(JexlEngine.Frame frame) { if (frame != null) { this.parameters = frame.getParameters(); this.registers = frame.getRegisters(); } else { this.parameters = null; this.registers = null; } } /** * Finds the node causing a NPE for diadic operators. * @param xrt the RuntimeException * @param node the parent node * @param left the left argument * @param right the right argument * @return the left, right or parent node */ protected JexlNode findNullOperand(RuntimeException xrt, JexlNode node, Object left, Object right) { if (xrt instanceof ArithmeticException && JexlException.NULL_OPERAND == xrt.getMessage()) { if (left == null) { return node.jjtGetChild(0); } if (right == null) { return node.jjtGetChild(1); } } return node; } /** * Triggered when variable can not be resolved. * @param xjexl the JexlException ("undefined variable " + variable) * @return throws JexlException if strict, null otherwise */ protected Object unknownVariable(JexlException xjexl) { if (strict) { throw xjexl; } if (!silent) { logger.warn(xjexl.getMessage()); } return null; } /** * Triggered when method, function or constructor invocation fails. * @param xjexl the JexlException wrapping the original error * @return throws JexlException if strict, null otherwise */ protected Object invocationFailed(JexlException xjexl) { if (strict || xjexl instanceof JexlException.Return) { throw xjexl; } if (!silent) { logger.warn(xjexl.getMessage(), xjexl.getCause()); } return null; } /** * Checks whether this interpreter execution was cancelled due to thread interruption. * @return true if cancelled, false otherwise * @since 2.1 */ protected boolean isCancelled() { if (cancelled | Thread.interrupted()) { cancelled = true; } return cancelled; } /** * Resolves a namespace, eventually allocating an instance using context as constructor argument. * The lifetime of such instances span the current expression or script evaluation. * * @param prefix the prefix name (may be null for global namespace) * @param node the AST node * @return the namespace instance */ protected Object resolveNamespace(String prefix, JexlNode node) { Object namespace = null; // check whether this namespace is a functor if (functors != null) { namespace = functors.get(prefix); if (namespace != null) { return namespace; } } // check if namespace if a resolver if (context instanceof NamespaceResolver) { namespace = ((NamespaceResolver) context).resolveNamespace(prefix); } if (namespace == null) { namespace = functions.get(prefix); if (prefix != null && namespace == null) { throw new JexlException(node, "no such function namespace " + prefix); } } // allow namespace to be instantiated as functor with context if possible, not an error otherwise if (namespace instanceof Class) { Object[] args = new Object[]{context}; JexlMethod ctor = uberspect.getConstructorMethod(namespace, args, node); if (ctor != null) { try { namespace = ctor.invoke(namespace, args); if (functors == null) { functors = new HashMap(); } functors.put(prefix, namespace); } catch (Exception xinst) { throw new JexlException(node, "unable to instantiate namespace " + prefix, xinst); } } } return namespace; } /** {@inheritDoc} */ public Object visit(ASTAdditiveNode node, Object data) { /** * The pattern for exception mgmt is to let the child*.jjtAccept * out of the try/catch loop so that if one fails, the ex will * traverse up to the interpreter. * In cases where this is not convenient/possible, JexlException must * be caught explicitly and rethrown. */ Object left = node.jjtGetChild(0).jjtAccept(this, data); for (int c = 2, size = node.jjtGetNumChildren(); c < size; c += 2) { Object right = node.jjtGetChild(c).jjtAccept(this, data); try { JexlNode op = node.jjtGetChild(c - 1); if (op instanceof ASTAdditiveOperator) { String which = op.image; if ("+".equals(which)) { left = arithmetic.add(left, right); continue; } if ("-".equals(which)) { left = arithmetic.subtract(left, right); continue; } throw new UnsupportedOperationException("unknown operator " + which); } throw new IllegalArgumentException("unknown operator " + op); } catch (ArithmeticException xrt) { JexlNode xnode = findNullOperand(xrt, node, left, right); throw new JexlException(xnode, "+/- error", xrt); } } return left; } /** {@inheritDoc} */ public Object visit(ASTAdditiveOperator node, Object data) { throw new UnsupportedOperationException("Shoud not be called."); } /** {@inheritDoc} */ public Object visit(ASTAndNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); try { boolean leftValue = arithmetic.toBoolean(left); if (!leftValue) { return Boolean.FALSE; } } catch (RuntimeException xrt) { throw new JexlException(node.jjtGetChild(0), "boolean coercion error", xrt); } Object right = node.jjtGetChild(1).jjtAccept(this, data); try { boolean rightValue = arithmetic.toBoolean(right); if (!rightValue) { return Boolean.FALSE; } } catch (ArithmeticException xrt) { throw new JexlException(node.jjtGetChild(1), "boolean coercion error", xrt); } return Boolean.TRUE; } /** {@inheritDoc} */ public Object visit(ASTArrayAccess node, Object data) { // first objectNode is the identifier Object object = node.jjtGetChild(0).jjtAccept(this, data); // can have multiple nodes - either an expression, integer literal or reference int numChildren = node.jjtGetNumChildren(); for (int i = 1; i < numChildren; i++) { JexlNode nindex = node.jjtGetChild(i); if (nindex instanceof JexlNode.Literal) { object = nindex.jjtAccept(this, object); } else { Object index = nindex.jjtAccept(this, null); object = getAttribute(object, index, nindex); } } return object; } /** {@inheritDoc} */ public Object visit(ASTArrayLiteral node, Object data) { Object literal = node.getLiteral(); if (literal == null) { int childCount = node.jjtGetNumChildren(); Object[] array = new Object[childCount]; for (int i = 0; i < childCount; i++) { Object entry = node.jjtGetChild(i).jjtAccept(this, data); array[i] = entry; } literal = arithmetic.narrowArrayType(array); node.setLiteral(literal); } return literal; } /** {@inheritDoc} */ public Object visit(ASTAssignment node, Object data) { // left contains the reference to assign to int register = -1; JexlNode left = node.jjtGetChild(0); if (left instanceof ASTIdentifier) { ASTIdentifier var = (ASTIdentifier) left; register = var.getRegister(); if (register < 0) { throw new JexlException(left, "unknown variable " + left.image); } } else if (!(left instanceof ASTReference)) { throw new JexlException(left, "illegal assignment form 0"); } // right is the value expression to assign Object right = node.jjtGetChild(1).jjtAccept(this, data); // determine initial object & property: JexlNode objectNode = null; Object object = register >= 0 ? registers[register] : null; JexlNode propertyNode = null; Object property = null; boolean isVariable = true; int v = 0; StringBuilder variableName = null; // 1: follow children till penultimate, resolve dot/array int last = left.jjtGetNumChildren() - 1; // check we are not assigning a register itself boolean isRegister = last < 0 && register >= 0; // start at 1 if register for (int c = register >= 0 ? 1 : 0; c < last; ++c) { objectNode = left.jjtGetChild(c); // evaluate the property within the object object = objectNode.jjtAccept(this, object); if (object != null) { continue; } isVariable &= objectNode instanceof ASTIdentifier || (objectNode instanceof ASTNumberLiteral && ((ASTNumberLiteral) objectNode).isInteger()); // if we get null back as a result, check for an ant variable if (isVariable) { if (v == 0) { variableName = new StringBuilder(left.jjtGetChild(0).image); v = 1; } for (; v <= c; ++v) { variableName.append('.'); variableName.append(left.jjtGetChild(v).image); } object = context.get(variableName.toString()); // disallow mixing ant & bean with same root; avoid ambiguity if (object != null) { isVariable = false; } } else { throw new JexlException(objectNode, "illegal assignment form"); } } // 2: last objectNode will perform assignement in all cases propertyNode = isRegister ? null : left.jjtGetChild(last); boolean antVar = false; if (propertyNode instanceof ASTIdentifier) { ASTIdentifier identifier = (ASTIdentifier) propertyNode; register = identifier.getRegister(); if (register >= 0) { isRegister = true; } else { property = identifier.image; antVar = true; } } else if (propertyNode instanceof ASTNumberLiteral && ((ASTNumberLiteral) propertyNode).isInteger()) { property = ((ASTNumberLiteral) propertyNode).getLiteral(); antVar = true; } else if (propertyNode instanceof ASTArrayAccess) { // first objectNode is the identifier objectNode = propertyNode; ASTArrayAccess narray = (ASTArrayAccess) objectNode; Object nobject = narray.jjtGetChild(0).jjtAccept(this, object); if (nobject == null) { throw new JexlException(objectNode, "array element is null"); } else { object = nobject; } // can have multiple nodes - either an expression, integer literal or // reference last = narray.jjtGetNumChildren() - 1; for (int i = 1; i < last; i++) { objectNode = narray.jjtGetChild(i); if (objectNode instanceof JexlNode.Literal) { object = objectNode.jjtAccept(this, object); } else { Object index = objectNode.jjtAccept(this, null); object = getAttribute(object, index, objectNode); } } property = narray.jjtGetChild(last).jjtAccept(this, null); } else if (!isRegister) { throw new JexlException(objectNode, "illegal assignment form"); } // deal with ant variable; set context if (isRegister) { registers[register] = right; return right; } else if (antVar) { if (isVariable && object == null) { if (variableName != null) { if (last > 0) { variableName.append('.'); } variableName.append(property); property = variableName.toString(); } try { context.set(String.valueOf(property), right); } catch (UnsupportedOperationException xsupport) { throw new JexlException(node, "context is readonly", xsupport); } return right; } } if (property == null) { // no property, we fail throw new JexlException(propertyNode, "property is null"); } if (object == null) { // no object, we fail throw new JexlException(objectNode, "bean is null"); } // one before last, assign setAttribute(object, property, right, propertyNode); return right; } /** {@inheritDoc} */ public Object visit(ASTBitwiseAndNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.bitwiseAnd(left, right); } catch (ArithmeticException xrt) { throw new JexlException(node, "& error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTBitwiseComplNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); try { return arithmetic.bitwiseComplement(left); } catch (ArithmeticException xrt) { throw new JexlException(node, "~ error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTBitwiseOrNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.bitwiseOr(left, right); } catch (ArithmeticException xrt) { throw new JexlException(node, "| error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTBitwiseXorNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.bitwiseXor(left, right); } catch (ArithmeticException xrt) { throw new JexlException(node, "^ error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTBlock node, Object data) { int numChildren = node.jjtGetNumChildren(); Object result = null; for (int i = 0; i < numChildren; i++) { result = node.jjtGetChild(i).jjtAccept(this, data); } return result; } /** {@inheritDoc} */ public Object visit(ASTDivNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.divide(left, right); } catch (ArithmeticException xrt) { if (!strict) { return new Double(0.0); } JexlNode xnode = findNullOperand(xrt, node, left, right); throw new JexlException(xnode, "divide error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTEmptyFunction node, Object data) { Object o = node.jjtGetChild(0).jjtAccept(this, data); if (o == null) { return Boolean.TRUE; } if (o instanceof String && "".equals(o)) { return Boolean.TRUE; } if (o.getClass().isArray() && ((Object[]) o).length == 0) { return Boolean.TRUE; } if (o instanceof Collection) { return ((Collection) o).isEmpty() ? Boolean.TRUE : Boolean.FALSE; } // Map isn't a collection if (o instanceof Map) { return ((Map) o).isEmpty() ? Boolean.TRUE : Boolean.FALSE; } return Boolean.FALSE; } /** {@inheritDoc} */ public Object visit(ASTEQNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE; } catch (ArithmeticException xrt) { throw new JexlException(node, "== error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTFalseNode node, Object data) { return Boolean.FALSE; } /** {@inheritDoc} */ public Object visit(ASTForeachStatement node, Object data) { Object result = null; /* first objectNode is the loop variable */ ASTReference loopReference = (ASTReference) node.jjtGetChild(0); ASTIdentifier loopVariable = (ASTIdentifier) loopReference.jjtGetChild(0); int register = loopVariable.getRegister(); /* second objectNode is the variable to iterate */ Object iterableValue = node.jjtGetChild(1).jjtAccept(this, data); // make sure there is a value to iterate on and a statement to execute if (iterableValue != null && node.jjtGetNumChildren() >= 3) { /* third objectNode is the statement to execute */ JexlNode statement = node.jjtGetChild(2); // get an iterator for the collection/array etc via the // introspector. Iterator itemsIterator = uberspect.getIterator(iterableValue, node); if (itemsIterator != null) { while (itemsIterator.hasNext()) { if (isCancelled()) { throw new JexlException.Cancel(node); } // set loopVariable to value of iterator Object value = itemsIterator.next(); if (register < 0) { context.set(loopVariable.image, value); } else { registers[register] = value; } // execute statement result = statement.jjtAccept(this, data); } } } return result; } /** {@inheritDoc} */ public Object visit(ASTGENode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.greaterThanOrEqual(left, right) ? Boolean.TRUE : Boolean.FALSE; } catch (ArithmeticException xrt) { throw new JexlException(node, ">= error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTGTNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.greaterThan(left, right) ? Boolean.TRUE : Boolean.FALSE; } catch (ArithmeticException xrt) { throw new JexlException(node, "> error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTERNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { // use arithmetic / pattern matching ? if (right instanceof java.util.regex.Pattern || right instanceof String) { return arithmetic.matches(left, right) ? Boolean.TRUE : Boolean.FALSE; } // left in right ? <=> right.contains(left) ? // try contains on collection if (right instanceof Set) { return ((Set) right).contains(left) ? Boolean.TRUE : Boolean.FALSE; } // try contains on map key if (right instanceof Map) { return ((Map) right).containsKey(left) ? Boolean.TRUE : Boolean.FALSE; } // try contains on collection if (right instanceof Collection) { return ((Collection) right).contains(left) ? Boolean.TRUE : Boolean.FALSE; } // try a contains method (duck type set) try { Object[] argv = {left}; JexlMethod vm = uberspect.getMethod(right, "contains", argv, node); if (vm != null) { return arithmetic.toBoolean(vm.invoke(right, argv)) ? Boolean.TRUE : Boolean.FALSE; } else if (arithmetic.narrowArguments(argv)) { vm = uberspect.getMethod(right, "contains", argv, node); if (vm != null) { return arithmetic.toBoolean(vm.invoke(right, argv)) ? Boolean.TRUE : Boolean.FALSE; } } } catch (InvocationTargetException e) { throw new JexlException(node, "=~ invocation error", e.getCause()); } catch (Exception e) { throw new JexlException(node, "=~ error", e); } // try iterative comparison Iterator it = uberspect.getIterator(right, node); if (it != null) { while (it.hasNext()) { Object next = it.next(); if (next == left || (next != null && next.equals(left))) { return Boolean.TRUE; } } return Boolean.FALSE; } // defaults to equal return arithmetic.equals(left, right) ? Boolean.TRUE : Boolean.FALSE; } catch (ArithmeticException xrt) { throw new JexlException(node, "=~ error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTIdentifier node, Object data) { if (isCancelled()) { throw new JexlException.Cancel(node); } String name = node.image; if (data == null) { int register = node.getRegister(); if (register >= 0) { return registers[register]; } Object value = context.get(name); if (value == null && !(node.jjtGetParent() instanceof ASTReference) && !context.has(name) && !isTernaryProtected(node)) { JexlException xjexl = new JexlException.Variable(node, name); return unknownVariable(xjexl); } return value; } else { return getAttribute(data, name, node); } } /** * @deprecated Do not use */ @Deprecated public Object visit(ASTFloatLiteral node, Object data) { throw new UnsupportedOperationException("Method should not be called; only present for API compatibiltiy"); } /** * @deprecated Do not use */ @Deprecated public Object visit(ASTIntegerLiteral node, Object data) { throw new UnsupportedOperationException("Method should not be called; only present for API compatibiltiy"); } /** {@inheritDoc} */ public Object visit(ASTVar node, Object data) { return visit((ASTIdentifier) node, data); } /** {@inheritDoc} */ public Object visit(ASTIfStatement node, Object data) { int n = 0; try { Object result = null; /* first objectNode is the condition */ Object expression = node.jjtGetChild(0).jjtAccept(this, data); if (arithmetic.toBoolean(expression)) { // first objectNode is true statement n = 1; result = node.jjtGetChild(1).jjtAccept(this, data); } else { // if there is a false, execute it. false statement is the second // objectNode if (node.jjtGetNumChildren() == 3) { n = 2; result = node.jjtGetChild(2).jjtAccept(this, data); } } return result; } catch (JexlException error) { throw error; } catch (ArithmeticException xrt) { throw new JexlException(node.jjtGetChild(n), "if error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTNumberLiteral node, Object data) { if (data != null && node.isInteger()) { return getAttribute(data, node.getLiteral(), node); } return node.getLiteral(); } /** {@inheritDoc} */ public Object visit(ASTJexlScript node, Object data) { int numChildren = node.jjtGetNumChildren(); Object result = null; for (int i = 0; i < numChildren; i++) { JexlNode child = node.jjtGetChild(i); result = child.jjtAccept(this, data); } return result; } /** {@inheritDoc} */ public Object visit(ASTLENode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.lessThanOrEqual(left, right) ? Boolean.TRUE : Boolean.FALSE; } catch (ArithmeticException xrt) { throw new JexlException(node, "<= error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTLTNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.lessThan(left, right) ? Boolean.TRUE : Boolean.FALSE; } catch (ArithmeticException xrt) { throw new JexlException(node, "< error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTMapEntry node, Object data) { Object key = node.jjtGetChild(0).jjtAccept(this, data); Object value = node.jjtGetChild(1).jjtAccept(this, data); return new Object[]{key, value}; } /** {@inheritDoc} */ public Object visit(ASTMapLiteral node, Object data) { int childCount = node.jjtGetNumChildren(); Map map = new HashMap(); for (int i = 0; i < childCount; i++) { Object[] entry = (Object[]) (node.jjtGetChild(i)).jjtAccept(this, data); map.put(entry[0], entry[1]); } return map; } /** * Calls a method (or function). *

* Method resolution is a follows: * 1 - attempt to find a method in the bean passed as parameter; * 2 - if this fails, narrow the arguments and try again * 3 - if this still fails, seeks a Script or JexlMethod as a property of that bean. *

* @param node the method node * @param bean the bean this method should be invoked upon * @param methodNode the node carrying the method name * @param argb the first argument index, child of the method node * @return the result of the method invocation */ private Object call(JexlNode node, Object bean, ASTIdentifier methodNode, int argb) { if (isCancelled()) { throw new JexlException.Cancel(node); } String methodName = methodNode.image; // evaluate the arguments int argc = node.jjtGetNumChildren() - argb; Object[] argv = new Object[argc]; for (int i = 0; i < argc; i++) { argv[i] = node.jjtGetChild(i + argb).jjtAccept(this, null); } JexlException xjexl = null; try { // attempt to reuse last executor cached in volatile JexlNode.value if (cache) { Object cached = node.jjtGetValue(); if (cached instanceof JexlMethod) { JexlMethod me = (JexlMethod) cached; Object eval = me.tryInvoke(methodName, bean, argv); if (!me.tryFailed(eval)) { return eval; } } } boolean cacheable = cache; JexlMethod vm = uberspect.getMethod(bean, methodName, argv, node); // DG: If we can't find an exact match, narrow the parameters and try again if (vm == null) { if (arithmetic.narrowArguments(argv)) { vm = uberspect.getMethod(bean, methodName, argv, node); } if (vm == null) { Object functor = null; // could not find a method, try as a var if (bean == context) { int register = methodNode.getRegister(); if (register >= 0) { functor = registers[register]; } else { functor = context.get(methodName); } } else { JexlPropertyGet gfunctor = uberspect.getPropertyGet(bean, methodName, node); if (gfunctor != null) { functor = gfunctor.tryInvoke(bean, methodName); } } // script of jexl method will do if (functor instanceof Script) { return ((Script) functor).execute(context, argv.length > 0 ? argv : null); } else if (functor instanceof JexlMethod) { vm = (JexlMethod) functor; cacheable = false; } else { xjexl = new JexlException.Method(node, methodName); } } } if (xjexl == null) { // vm cannot be null if xjexl is null Object eval = vm.invoke(bean, argv); // cache executor in volatile JexlNode.value if (cacheable && vm.isCacheable()) { node.jjtSetValue(vm); } return eval; } } catch (InvocationTargetException e) { xjexl = new JexlException(node, "method invocation error", e.getCause()); } catch (Exception e) { xjexl = new JexlException(node, "method error", e); } return invocationFailed(xjexl); } /** {@inheritDoc} */ public Object visit(ASTMethodNode node, Object data) { // the object to invoke the method on should be in the data argument if (data == null) { // if the method node is the first child of the (ASTReference) parent, // it is considered as calling a 'top level' function if (node.jjtGetParent().jjtGetChild(0) == node) { data = resolveNamespace(null, node); if (data == null) { data = context; } } else { throw new JexlException(node, "attempting to call method on null"); } } // objectNode 0 is the identifier (method name), the others are parameters. ASTIdentifier methodNode = (ASTIdentifier) node.jjtGetChild(0); return call(node, data, methodNode, 1); } /** {@inheritDoc} */ public Object visit(ASTFunctionNode node, Object data) { // objectNode 0 is the prefix String prefix = node.jjtGetChild(0).image; Object namespace = resolveNamespace(prefix, node); // objectNode 1 is the identifier , the others are parameters. ASTIdentifier functionNode = (ASTIdentifier) node.jjtGetChild(1); return call(node, namespace, functionNode, 2); } /** {@inheritDoc} */ public Object visit(ASTConstructorNode node, Object data) { if (isCancelled()) { throw new JexlException.Cancel(node); } // first child is class or class name Object cobject = node.jjtGetChild(0).jjtAccept(this, data); // get the ctor args int argc = node.jjtGetNumChildren() - 1; Object[] argv = new Object[argc]; for (int i = 0; i < argc; i++) { argv[i] = node.jjtGetChild(i + 1).jjtAccept(this, null); } JexlException xjexl = null; try { // attempt to reuse last constructor cached in volatile JexlNode.value if (cache) { Object cached = node.jjtGetValue(); if (cached instanceof JexlMethod) { JexlMethod mctor = (JexlMethod) cached; Object eval = mctor.tryInvoke(null, cobject, argv); if (!mctor.tryFailed(eval)) { return eval; } } } JexlMethod ctor = uberspect.getConstructorMethod(cobject, argv, node); // DG: If we can't find an exact match, narrow the parameters and try again if (ctor == null) { if (arithmetic.narrowArguments(argv)) { ctor = uberspect.getConstructorMethod(cobject, argv, node); } if (ctor == null) { xjexl = new JexlException.Method(node, cobject.toString()); } } if (xjexl == null) { Object instance = ctor.invoke(cobject, argv); // cache executor in volatile JexlNode.value if (cache && ctor.isCacheable()) { node.jjtSetValue(ctor); } return instance; } } catch (InvocationTargetException e) { xjexl = new JexlException(node, "constructor invocation error", e.getCause()); } catch (Exception e) { xjexl = new JexlException(node, "constructor error", e); } return invocationFailed(xjexl); } /** {@inheritDoc} */ public Object visit(ASTModNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.mod(left, right); } catch (ArithmeticException xrt) { if (!strict) { return new Double(0.0); } JexlNode xnode = findNullOperand(xrt, node, left, right); throw new JexlException(xnode, "% error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTMulNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.multiply(left, right); } catch (ArithmeticException xrt) { JexlNode xnode = findNullOperand(xrt, node, left, right); throw new JexlException(xnode, "* error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTNENode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { return arithmetic.equals(left, right) ? Boolean.FALSE : Boolean.TRUE; } catch (ArithmeticException xrt) { JexlNode xnode = findNullOperand(xrt, node, left, right); throw new JexlException(xnode, "!= error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTNRNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); Object right = node.jjtGetChild(1).jjtAccept(this, data); try { if (right instanceof java.util.regex.Pattern || right instanceof String) { // use arithmetic / pattern matching return arithmetic.matches(left, right) ? Boolean.FALSE : Boolean.TRUE; } // try contains on collection if (right instanceof Set) { return ((Set) right).contains(left) ? Boolean.FALSE : Boolean.TRUE; } // try contains on map key if (right instanceof Map) { return ((Map) right).containsKey(left) ? Boolean.FALSE : Boolean.TRUE; } // try contains on collection if (right instanceof Collection) { return ((Collection) right).contains(left) ? Boolean.FALSE : Boolean.TRUE; } // try a contains method (duck type set) try { Object[] argv = {left}; JexlMethod vm = uberspect.getMethod(right, "contains", argv, node); if (vm != null) { return arithmetic.toBoolean(vm.invoke(right, argv)) ? Boolean.FALSE : Boolean.TRUE; } else if (arithmetic.narrowArguments(argv)) { vm = uberspect.getMethod(right, "contains", argv, node); if (vm != null) { return arithmetic.toBoolean(vm.invoke(right, argv)) ? Boolean.FALSE : Boolean.TRUE; } } } catch (InvocationTargetException e) { throw new JexlException(node, "!~ invocation error", e.getCause()); } catch (Exception e) { throw new JexlException(node, "!~ error", e); } // try iterative comparison Iterator it = uberspect.getIterator(right, node.jjtGetChild(1)); if (it != null) { while (it.hasNext()) { Object next = it.next(); if (next == left || (next != null && next.equals(left))) { return Boolean.FALSE; } } return Boolean.TRUE; } // defaults to not equal return arithmetic.equals(left, right) ? Boolean.FALSE : Boolean.TRUE; } catch (ArithmeticException xrt) { throw new JexlException(node, "!~ error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTNotNode node, Object data) { Object val = node.jjtGetChild(0).jjtAccept(this, data); return arithmetic.toBoolean(val) ? Boolean.FALSE : Boolean.TRUE; } /** {@inheritDoc} */ public Object visit(ASTNullLiteral node, Object data) { return null; } /** {@inheritDoc} */ public Object visit(ASTOrNode node, Object data) { Object left = node.jjtGetChild(0).jjtAccept(this, data); try { boolean leftValue = arithmetic.toBoolean(left); if (leftValue) { return Boolean.TRUE; } } catch (ArithmeticException xrt) { throw new JexlException(node.jjtGetChild(0), "boolean coercion error", xrt); } Object right = node.jjtGetChild(1).jjtAccept(this, data); try { boolean rightValue = arithmetic.toBoolean(right); if (rightValue) { return Boolean.TRUE; } } catch (ArithmeticException xrt) { throw new JexlException(node.jjtGetChild(1), "boolean coercion error", xrt); } return Boolean.FALSE; } /** {@inheritDoc} */ public Object visit(ASTReference node, Object data) { // could be array access, identifier or map literal // followed by zero or more ("." and array access, method, size, // identifier or integer literal) int numChildren = node.jjtGetNumChildren(); // pass first piece of data in and loop through children Object result = null; StringBuilder variableName = null; String propertyName = null; boolean isVariable = true; int v = 0; for (int c = 0; c < numChildren; c++) { if (isCancelled()) { throw new JexlException.Cancel(node); } JexlNode theNode = node.jjtGetChild(c); // integer literals may be part of an antish var name only if no bean was found so far if (result == null && theNode instanceof ASTNumberLiteral && ((ASTNumberLiteral) theNode).isInteger()) { isVariable &= v > 0; } else { isVariable &= (theNode instanceof ASTIdentifier); result = theNode.jjtAccept(this, result); } // if we get null back a result, check for an ant variable if (result == null && isVariable) { if (v == 0) { variableName = new StringBuilder(node.jjtGetChild(0).image); v = 1; } for (; v <= c; ++v) { variableName.append('.'); variableName.append(node.jjtGetChild(v).image); } result = context.get(variableName.toString()); } else { propertyName = theNode.image; } } if (result == null) { if (isVariable && !isTernaryProtected(node) // variable unknow in context and not (from) a register && !(context.has(variableName.toString()) || (numChildren == 1 && node.jjtGetChild(0) instanceof ASTIdentifier && ((ASTIdentifier) node.jjtGetChild(0)).getRegister() >= 0))) { JexlException xjexl = propertyName != null ? new JexlException.Property(node, propertyName) : new JexlException.Variable(node, variableName.toString()); return unknownVariable(xjexl); } } return result; } /** * {@inheritDoc} * @since 2.1 */ public Object visit(ASTReferenceExpression node, Object data) { ASTArrayAccess upper = node; return visit(upper, data); } /** * {@inheritDoc} * @since 2.1 */ public Object visit(ASTReturnStatement node, Object data) { Object val = node.jjtGetChild(0).jjtAccept(this, data); throw new JexlException.Return(node, null, val); } /** * Check if a null evaluated expression is protected by a ternary expression. * The rationale is that the ternary / elvis expressions are meant for the user to explictly take * control over the error generation; ie, ternaries can return null even if the engine in strict mode * would normally throw an exception. * @param node the expression node * @return true if nullable variable, false otherwise */ private boolean isTernaryProtected(JexlNode node) { for (JexlNode walk = node.jjtGetParent(); walk != null; walk = walk.jjtGetParent()) { if (walk instanceof ASTTernaryNode) { return true; } else if (!(walk instanceof ASTReference || walk instanceof ASTArrayAccess)) { break; } } return false; } /** {@inheritDoc} */ public Object visit(ASTSizeFunction node, Object data) { Object val = node.jjtGetChild(0).jjtAccept(this, data); if (val == null) { throw new JexlException(node, "size() : argument is null", null); } return Integer.valueOf(sizeOf(node, val)); } /** {@inheritDoc} */ public Object visit(ASTSizeMethod node, Object data) { return Integer.valueOf(sizeOf(node, data)); } /** {@inheritDoc} */ public Object visit(ASTStringLiteral node, Object data) { if (data != null) { return getAttribute(data, node.getLiteral(), node); } return node.image; } /** {@inheritDoc} */ public Object visit(ASTTernaryNode node, Object data) { Object condition = node.jjtGetChild(0).jjtAccept(this, data); if (node.jjtGetNumChildren() == 3) { if (condition != null && arithmetic.toBoolean(condition)) { return node.jjtGetChild(1).jjtAccept(this, data); } else { return node.jjtGetChild(2).jjtAccept(this, data); } } if (condition != null && arithmetic.toBoolean(condition)) { return condition; } else { return node.jjtGetChild(1).jjtAccept(this, data); } } /** {@inheritDoc} */ public Object visit(ASTTrueNode node, Object data) { return Boolean.TRUE; } /** {@inheritDoc} */ public Object visit(ASTUnaryMinusNode node, Object data) { JexlNode valNode = node.jjtGetChild(0); Object val = valNode.jjtAccept(this, data); try { Object number = arithmetic.negate(val); // attempt to recoerce to literal class if (valNode instanceof ASTNumberLiteral && number instanceof Number) { number = arithmetic.narrowNumber((Number) number, ((ASTNumberLiteral) valNode).getLiteralClass()); } return number; } catch (ArithmeticException xrt) { throw new JexlException(valNode, "arithmetic error", xrt); } } /** {@inheritDoc} */ public Object visit(ASTWhileStatement node, Object data) { Object result = null; /* first objectNode is the expression */ Node expressionNode = node.jjtGetChild(0); while (arithmetic.toBoolean(expressionNode.jjtAccept(this, data))) { if (isCancelled()) { throw new JexlException.Cancel(node); } // execute statement if (node.jjtGetNumChildren() > 1) { result = node.jjtGetChild(1).jjtAccept(this, data); } } return result; } /** * Calculate the size of various types: Collection, Array, * Map, String, and anything that has a int size() method. * @param node the node that gave the value to size * @param val the object to get the size of. * @return the size of val */ private int sizeOf(JexlNode node, Object val) { if (val instanceof Collection) { return ((Collection) val).size(); } else if (val.getClass().isArray()) { return Array.getLength(val); } else if (val instanceof Map) { return ((Map) val).size(); } else if (val instanceof String) { return ((String) val).length(); } else { // check if there is a size method on the object that returns an // integer and if so, just use it Object[] params = new Object[0]; JexlMethod vm = uberspect.getMethod(val, "size", EMPTY_PARAMS, node); if (vm != null && vm.getReturnType() == Integer.TYPE) { Integer result; try { result = (Integer) vm.invoke(val, params); } catch (Exception e) { throw new JexlException(node, "size() : error executing", e); } return result.intValue(); } throw new JexlException(node, "size() : unsupported type : " + val.getClass(), null); } } /** * Gets an attribute of an object. * * @param object to retrieve value from * @param attribute the attribute of the object, e.g. an index (1, 0, 2) or * key for a map * @return the attribute value */ public Object getAttribute(Object object, Object attribute) { return getAttribute(object, attribute, null); } /** * Gets an attribute of an object. * * @param object to retrieve value from * @param attribute the attribute of the object, e.g. an index (1, 0, 2) or * key for a map * @param node the node that evaluated as the object * @return the attribute value */ protected Object getAttribute(Object object, Object attribute, JexlNode node) { if (object == null) { throw new JexlException(node, "object is null"); } if (isCancelled()) { throw new JexlException.Cancel(node); } // attempt to reuse last executor cached in volatile JexlNode.value if (node != null && cache) { Object cached = node.jjtGetValue(); if (cached instanceof JexlPropertyGet) { JexlPropertyGet vg = (JexlPropertyGet) cached; Object value = vg.tryInvoke(object, attribute); if (!vg.tryFailed(value)) { return value; } } } JexlPropertyGet vg = uberspect.getPropertyGet(object, attribute, node); if (vg != null) { try { Object value = vg.invoke(object); // cache executor in volatile JexlNode.value if (node != null && cache && vg.isCacheable()) { node.jjtSetValue(vg); } return value; } catch (Exception xany) { if (node == null) { throw new RuntimeException(xany); } else { JexlException xjexl = new JexlException.Property(node, attribute.toString()); if (strict) { throw xjexl; } if (!silent) { logger.warn(xjexl.getMessage()); } } } } return null; } /** * Sets an attribute of an object. * * @param object to set the value to * @param attribute the attribute of the object, e.g. an index (1, 0, 2) or * key for a map * @param value the value to assign to the object's attribute */ public void setAttribute(Object object, Object attribute, Object value) { setAttribute(object, attribute, value, null); } /** * Sets an attribute of an object. * * @param object to set the value to * @param attribute the attribute of the object, e.g. an index (1, 0, 2) or * key for a map * @param value the value to assign to the object's attribute * @param node the node that evaluated as the object */ protected void setAttribute(Object object, Object attribute, Object value, JexlNode node) { if (isCancelled()) { throw new JexlException.Cancel(node); } // attempt to reuse last executor cached in volatile JexlNode.value if (node != null && cache) { Object cached = node.jjtGetValue(); if (cached instanceof JexlPropertySet) { JexlPropertySet setter = (JexlPropertySet) cached; Object eval = setter.tryInvoke(object, attribute, value); if (!setter.tryFailed(eval)) { return; } } } JexlException xjexl = null; JexlPropertySet vs = uberspect.getPropertySet(object, attribute, value, node); // if we can't find an exact match, narrow the value argument and try again if (vs == null) { // replace all numbers with the smallest type that will fit Object[] narrow = {value}; if (arithmetic.narrowArguments(narrow)) { vs = uberspect.getPropertySet(object, attribute, narrow[0], node); } } if (vs != null) { try { // cache executor in volatile JexlNode.value vs.invoke(object, value); if (node != null && cache && vs.isCacheable()) { node.jjtSetValue(vs); } return; } catch (RuntimeException xrt) { if (node == null) { throw xrt; } xjexl = new JexlException(node, "set object property error", xrt); } catch (Exception xany) { if (node == null) { throw new RuntimeException(xany); } xjexl = new JexlException(node, "set object property error", xany); } } if (xjexl == null) { if (node == null) { String error = "unable to set object property" + ", class: " + object.getClass().getName() + ", property: " + attribute + ", argument: " + value.getClass().getSimpleName(); throw new UnsupportedOperationException(error); } xjexl = new JexlException.Property(node, attribute.toString()); } if (strict) { throw xjexl; } if (!silent) { logger.warn(xjexl.getMessage()); } } /** * Unused, satisfy ParserVisitor interface. * @param node a node * @param data the data * @return does not return */ public Object visit(SimpleNode node, Object data) { throw new UnsupportedOperationException("Not supported yet."); } /** * Unused, should throw in Parser. * @param node a node * @param data the data * @return does not return */ public Object visit(ASTAmbiguous node, Object data) { throw new UnsupportedOperationException("unexpected type of node"); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/introspection/JexlMethod.java100644 0 0 4751 11673634323 27032 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.introspection; /** * Interface used for regular method invocation. * Ex. * * ${foo.bar()} * * * @since 1.0 */ public interface JexlMethod { /** * Invocation method, called when the method invocation should be performed * and a value returned. * @param obj the object * @param params method parameters. * @return the result * @throws Exception on any error. */ Object invoke(Object obj, Object[] params) throws Exception; /** * Attempts to reuse this JexlMethod, checking that it is compatible with * the actual set of arguments. * Related to isCacheable since this method is often used with cached JexlMethod instances. * @param obj the object to invoke the method upon * @param name the method name * @param params the method arguments * @return the result of the method invocation that should be checked by tryFailed to determine if it succeeded * or failed. */ Object tryInvoke(String name, Object obj, Object[] params); /** * Checks whether a tryInvoke failed or not. * @param rval the value returned by tryInvoke * @return true if tryInvoke failed, false otherwise */ boolean tryFailed(Object rval); /** * Specifies if this JexlMethod is cacheable and able to be reused for this * class of object it was returned for. * * @return true if can be reused for this class, false if not */ boolean isCacheable(); /** * returns the return type of the method invoked. * @return return type */ Class getReturnType(); }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertyGet.java100644 0 0 4253 11673634323 30073 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.introspection; /** * Interface for getting values that appear to be properties. * Ex. * * ${foo.bar} * * @since 1.0 */ public interface JexlPropertyGet { /** * Method used to get the property value of an object. * * @param obj the object to get the property value from. * @return the property value. * @throws Exception on any error. */ Object invoke(Object obj) throws Exception; /** * Attempts to reuse this JexlPropertyGet, checking that it is compatible with * the actual set of arguments. * @param obj the object to invoke the property get upon * @param key the property key to get * @return the result of the method invocation that should be checked by tryFailed to determine if it succeeded * or failed. */ Object tryInvoke(Object obj, Object key); /** * Checks whether a tryInvoke failed or not. * @param rval the value returned by tryInvoke * @return true if tryInvoke failed, false otherwise */ boolean tryFailed(Object rval); /** * Specifies if this JexlPropertyGet is cacheable and able to be reused for * this class of object it was returned for. * * @return true if can be reused for this class, false if not */ boolean isCacheable(); } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/introspection/JexlPropertySet.java100644 0 0 4543 11673634323 30111 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.introspection; /** * Interface used for setting values that appear to be properties. * Ex. * * ${foo.bar = "hello"} * * @since 1.0 */ public interface JexlPropertySet { /** * Method used to set the property value of an object. * * @param obj Object on which the property setter will be called with the value * @param arg value to be set * @return the value returned from the set operation (impl specific) * @throws Exception on any error. */ Object invoke(Object obj, Object arg) throws Exception; /** * Attempts to reuse this JexlPropertySet, checking that it is compatible with * the actual set of arguments. * @param obj the object to invoke the the get upon * @param key the property key to get * @param value the property value to set * @return the result of the method invocation that should be checked by tryFailed to determine if it succeeded * or failed. */ Object tryInvoke(Object obj, Object key, Object value); /** * Checks whether a tryInvoke failed or not. * @param rval the value returned by tryInvoke * @return true if tryInvoke failed, false otherwise */ boolean tryFailed(Object rval); /** * Specifies if this JexlPropertySet is cacheable and able to be reused for * this class of object it was returned for. * * @return true if can be reused for this class, false if not */ boolean isCacheable(); } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/introspection/package.html100644 0 0 3132 11673634323 26375 0ustar 0 0 Package Documentation for org.apache.commons.jexl2.introspection Package

Provides high-level introspective services.

The Uberspect, JexlMethod, JexlPropertyGet and JexlPropertySet interfaces form the exposed face of introspective services.

The Uberspectimpl is the concrete class implementing the Uberspect interface. Deriving from this class is the preferred way of augmenting Jexl introspective capabilities when special needs to be fullfilled or when default behaviors need to be modified.

commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/introspection/Sandbox.java100644 0 0 31730 11673634323 26402 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.introspection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * A sandbox describes permissions on a class by explicitly allowing or forbidding access to methods and properties * through "whitelists" and "blacklists". *

* A whitelist explicitly allows methods/properties for a class; *

    *
  • * If a whitelist is empty and thus does not contain any names, all properties/methods are allowed for its class. *
  • *
  • * If it is not empty, the only allowed properties/methods are the ones contained. *
  • *
*

*

* A blacklist explicitly forbids methods/properties for a class; *

    *
  • * If a blacklist is empty and thus does not contain any names, all properties/methods are forbidden for its class. *
  • *
  • * If it is not empty, the only forbidden properties/methods are the ones contained. *
  • *
*

* Permissions are composed of three lists, read, write, execute, each being "white" or "black": *

    *
  • read controls readable properties
  • *
  • write controls writeable properties
  • *
  • execute controls executable methods and constructor
  • *
*

* @since 2.1 */ public final class Sandbox { /** * The map from class names to permissions. */ private final Map sandbox; /** * Creates a new default sandbox. */ public Sandbox() { this(new HashMap()); } /** * Creates a sandbox based on an existing permissions map. * @param map the permissions map */ protected Sandbox(Map map) { sandbox = map; } /** * Gets the read permission value for a given property of a class. * @param clazz the class * @param name the property name * @return null if not allowed, the name of the property to use otherwise */ public String read(Class clazz, String name) { return read(clazz.getName(), name); } /** * Gets the read permission value for a given property of a class. * @param clazz the class name * @param name the property name * @return null if not allowed, the name of the property to use otherwise */ public String read(String clazz, String name) { Permissions permissions = sandbox.get(clazz); if (permissions == null) { return name; } else { return permissions.read().get(name); } } /** * Gets the write permission value for a given property of a class. * @param clazz the class * @param name the property name * @return null if not allowed, the name of the property to use otherwise */ public String write(Class clazz, String name) { return write(clazz.getName(), name); } /** * Gets the write permission value for a given property of a class. * @param clazz the class name * @param name the property name * @return null if not allowed, the name of the property to use otherwise */ public String write(String clazz, String name) { Permissions permissions = sandbox.get(clazz); if (permissions == null) { return name; } else { return permissions.write().get(name); } } /** * Gets the execute permission value for a given method of a class. * @param clazz the class * @param name the method name * @return null if not allowed, the name of the method to use otherwise */ public String execute(Class clazz, String name) { return execute(clazz.getName(), name); } /** * Gets the execute permission value for a given method of a class. * @param clazz the class name * @param name the method name * @return null if not allowed, the name of the method to use otherwise */ public String execute(String clazz, String name) { Permissions permissions = sandbox.get(clazz); if (permissions == null) { return name; } else { return permissions.execute().get(name); } } /** * A base set of names. */ public abstract static class Names { /** * Adds a name to this set. * @param name the name to add * @return true if the name was really added, false if not */ public abstract boolean add(String name); /** * Adds an alias to a name to this set. *

This only has an effect on white lists.

* @param name the name to alias * @param alias the alias * @return true if the alias was added, false if it was already present */ public boolean alias(String name, String alias) { return false; } /** * Whether a given name is allowed or not. * @param name the method/property name to check * @return null if not allowed, the actual name to use otherwise */ public String get(String name) { return name; } } /** * The pass-thru name set. */ private static final Names WHITE_NAMES = new Names() { @Override public boolean add(String name) { return false; } }; /** * A white set of names. */ public static final class WhiteSet extends Names { /** The map of controlled names and aliases. */ private Map names = null; @Override public boolean add(String name) { if (names == null) { names = new HashMap(); } return names.put(name, name) == null; } @Override public boolean alias(String name, String alias) { if (names == null) { names = new HashMap(); } return names.put(alias, name) == null; } @Override public String get(String name) { if (names == null) { return name; } else { return names.get(name); } } } /** * A black set of names. */ public static final class BlackSet extends Names { /** The set of controlled names. */ private Set names = null; @Override public boolean add(String name) { if (names == null) { names = new HashSet(); } return names.add(name); } @Override public String get(String name) { return names != null && !names.contains(name) ? name : null; } } /** * Contains the white or black lists for properties and methods for a given class. */ public static final class Permissions { /** The controlled readable properties. */ private final Names read; /** The controlled writeable properties. */ private final Names write; /** The controlled methods. */ private final Names execute; /** * Creates a new permissions instance. * @param readFlag whether the read property list is white or black * @param writeFlag whether the write property list is white or black * @param executeFlag whether the method list is white of black */ Permissions(boolean readFlag, boolean writeFlag, boolean executeFlag) { this(readFlag ? new WhiteSet() : new BlackSet(), writeFlag ? new WhiteSet() : new BlackSet(), executeFlag ? new WhiteSet() : new BlackSet()); } /** * Creates a new permissions instance. * @param nread the read set * @param nwrite the write set * @param nexecute the method set */ Permissions(Names nread, Names nwrite, Names nexecute) { this.read = nread != null ? nread : WHITE_NAMES; this.write = nwrite != null ? nwrite : WHITE_NAMES; this.execute = nexecute != null ? nexecute : WHITE_NAMES; } /** * Adds a list of readable property names to these permissions. * @param pnames the property names * @return this instance of permissions */ public Permissions read(String... pnames) { for (String pname : pnames) { read.add(pname); } return this; } /** * Adds a list of writeable property names to these permissions. * @param pnames the property names * @return this instance of permissions */ public Permissions write(String... pnames) { for (String pname : pnames) { write.add(pname); } return this; } /** * Adds a list of executable methods names to these permissions. *

The constructor is denoted as the empty-string, all other methods by their names.

* @param mnames the method names * @return this instance of permissions */ public Permissions execute(String... mnames) { for (String mname : mnames) { execute.add(mname); } return this; } /** * Gets the set of readable property names in these permissions. * @return the set of property names */ public Names read() { return read; } /** * Gets the set of writeable property names in these permissions. * @return the set of property names */ public Names write() { return write; } /** * Gets the set of method names in these permissions. * @return the set of method names */ public Names execute() { return execute; } } /** * The pass-thru permissions. */ private static final Permissions ALL_WHITE = new Permissions(WHITE_NAMES, WHITE_NAMES, WHITE_NAMES); /** * Creates the set of permissions for a given class. * @param clazz the class for which these permissions apply * @param readFlag whether the readable property list is white - true - or black - false - * @param writeFlag whether the writeable property list is white - true - or black - false - * @param executeFlag whether the executable method list is white white - true - or black - false - * @return the set of permissions */ public Permissions permissions(String clazz, boolean readFlag, boolean writeFlag, boolean executeFlag) { Permissions box = new Permissions(readFlag, writeFlag, executeFlag); sandbox.put(clazz, box); return box; } /** * Creates a new set of permissions based on white lists for methods and properties for a given class. * @param clazz the whitened class name * @return the permissions instance */ public Permissions white(String clazz) { return permissions(clazz, true, true, true); } /** * Creates a new set of permissions based on black lists for methods and properties for a given class. * @param clazz the blackened class name * @return the permissions instance */ public Permissions black(String clazz) { return permissions(clazz, false, false, false); } /** * Gets the set of permissions associated to a class. * @param clazz the class name * @return the defined permissions or an all-white permission instance if none were defined */ public Permissions get(String clazz) { Permissions permissions = sandbox.get(clazz); if (permissions == null) { return ALL_WHITE; } else { return permissions; } } } ././@LongLink100644 0 0 146 11673650055 10264 Lustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/introspection/SandboxUberspectImpl.javacommons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/introspection/SandboxUberspectImpl.jav100644 0 0 7321 11673634323 30717 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.introspection; import org.apache.commons.jexl2.JexlInfo; import org.apache.commons.logging.Log; /** * An uberspect that controls usage of properties, methods and contructors through a sandbox. * @since 2.1 */ public class SandboxUberspectImpl extends UberspectImpl { /** The sandbox. */ protected final Sandbox sandbox; /** * A constructor for Sandbox uberspect. * @param runtimeLogger the logger to use or null to use default * @param theSandbox the sandbox instance to use */ public SandboxUberspectImpl(Log runtimeLogger, Sandbox theSandbox) { super(runtimeLogger); if (theSandbox == null) { throw new NullPointerException("sandbox can not be null"); } this.sandbox = theSandbox; } /** * {@inheritDoc} */ @Override public void setLoader(ClassLoader cloader) { base().setLoader(cloader); } /** * {@inheritDoc} */ @Override public JexlMethod getConstructorMethod(Object ctorHandle, Object[] args, JexlInfo info) { final String className; if (ctorHandle instanceof Class) { Class clazz = (Class) ctorHandle; className = clazz.getName(); } else if (ctorHandle != null) { className = ctorHandle.toString(); } else { return null; } if (sandbox.execute(className, "") != null) { return super.getConstructorMethod(className, args, info); } return null; } /** * {@inheritDoc} */ @Override public JexlMethod getMethod(Object obj, String method, Object[] args, JexlInfo info) { if (obj != null && method != null) { String actual = sandbox.execute(obj.getClass().getName(), method); if (actual != null) { return getMethodExecutor(obj, actual, args); } } return null; } /** * {@inheritDoc} */ @Override public JexlPropertyGet getPropertyGet(Object obj, Object identifier, JexlInfo info) { if (obj != null && identifier != null) { String actual = sandbox.read(obj.getClass().getName(), identifier.toString()); if (actual != null) { return super.getPropertyGet(obj, actual, info); } } return null; } /** * {@inheritDoc} */ @Override public JexlPropertySet getPropertySet(final Object obj, final Object identifier, Object arg, JexlInfo info) { if (obj != null && identifier != null) { String actual = sandbox.write(obj.getClass().getName(), identifier.toString()); if (actual != null) { return super.getPropertySet(obj, actual, arg, info); } } return null; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/introspection/Uberspect.java100644 0 0 6525 11673634323 26724 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.introspection; import java.lang.reflect.Constructor; import java.util.Iterator; import org.apache.commons.jexl2.JexlInfo; /** * 'Federated' introspection/reflection interface to allow the introspection * behavior in JEXL to be customized. * * @since 1.0 */ public interface Uberspect { /** Sets the class loader to use when getting a constructor with * a class name parameter. * @param loader the class loader */ void setClassLoader(ClassLoader loader); /** * Returns a class constructor. * @param ctorHandle a class or class name * @param args constructor arguments * @param info contextual information * @return a {@link Constructor} */ @Deprecated Constructor getConstructor(Object ctorHandle, Object[] args, JexlInfo info); /** * Returns a class constructor wrapped in a JexlMethod. * @param ctorHandle a class or class name * @param args constructor arguments * @param info contextual information * @return a {@link Constructor} * @since 2.1 */ JexlMethod getConstructorMethod(Object ctorHandle, Object[] args, JexlInfo info); /** * Returns a JexlMethod. * @param obj the object * @param method the method name * @param args method arguments * @param info contextual information * @return a {@link JexlMethod} */ JexlMethod getMethod(Object obj, String method, Object[] args, JexlInfo info); /** * Property getter. *

Returns JexlPropertyGet appropos for ${bar.woogie}. * @param obj the object to get the property from * @param identifier property name * @param info contextual information * @return a {@link JexlPropertyGet} */ JexlPropertyGet getPropertyGet(Object obj, Object identifier, JexlInfo info); /** * Property setter. *

returns JelPropertySet appropos for ${foo.bar = "geir"}

. * @param obj the object to get the property from. * @param identifier property name * @param arg value to set * @param info contextual information * @return a {@link JexlPropertySet}. */ JexlPropertySet getPropertySet(Object obj, Object identifier, Object arg, JexlInfo info); /** * Gets an iterator from an object. * @param obj to get the iterator for * @param info contextual information * @return an iterator over obj */ Iterator getIterator(Object obj, JexlInfo info); }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/introspection/UberspectImpl.java100644 0 0 45652 11673634323 27572 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.introspection; import java.beans.IntrospectionException; import org.apache.commons.jexl2.internal.Introspector; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Enumeration; import java.util.Iterator; import java.util.Map; import org.apache.commons.jexl2.JexlInfo; import org.apache.commons.jexl2.JexlException; import org.apache.commons.jexl2.internal.AbstractExecutor; import org.apache.commons.jexl2.internal.ArrayIterator; import org.apache.commons.jexl2.internal.EnumerationIterator; import org.apache.commons.jexl2.internal.introspection.MethodKey; import org.apache.commons.logging.Log; /** * Implementation of Uberspect to provide the default introspective * functionality of JEXL. *

This is the class to derive to customize introspection.

* * @since 1.0 */ public class UberspectImpl extends Introspector implements Uberspect { /** * Publicly exposed special failure object returned by tryInvoke. */ public static final Object TRY_FAILED = AbstractExecutor.TRY_FAILED; /** * Creates a new UberspectImpl. * @param runtimeLogger the logger used for all logging needs */ public UberspectImpl(Log runtimeLogger) { super(runtimeLogger); } /** * Resets this Uberspect class loader. * @param cloader the class loader to use * @since 2.1 */ public void setLoader(ClassLoader cloader) { base().setLoader(cloader); } /** * {@inheritDoc} */ @SuppressWarnings("unchecked") public Iterator getIterator(Object obj, JexlInfo info) { if (obj instanceof Iterator) { return ((Iterator) obj); } if (obj.getClass().isArray()) { return new ArrayIterator(obj); } if (obj instanceof Map) { return ((Map) obj).values().iterator(); } if (obj instanceof Enumeration) { return new EnumerationIterator((Enumeration) obj); } if (obj instanceof Iterable) { return ((Iterable) obj).iterator(); } try { // look for an iterator() method to support the JDK5 Iterable // interface or any user tools/DTOs that want to work in // foreach without implementing the Collection interface AbstractExecutor.Method it = getMethodExecutor(obj, "iterator", null); if (it != null && Iterator.class.isAssignableFrom(it.getReturnType())) { return (Iterator) it.execute(obj, null); } } catch (Exception xany) { throw new JexlException(info, "unable to generate iterator()", xany); } return null; } /** * {@inheritDoc} */ public JexlMethod getMethod(Object obj, String method, Object[] args, JexlInfo info) { return getMethodExecutor(obj, method, args); } /** * {@inheritDoc} */ @Deprecated public Constructor getConstructor(Object ctorHandle, Object[] args, JexlInfo info) { return getConstructor(ctorHandle, args); } /** * {@inheritDoc} * @since 2.1 */ public JexlMethod getConstructorMethod(Object ctorHandle, Object[] args, JexlInfo info) { final Constructor ctor = getConstructor(ctorHandle, args); if (ctor != null) { return new ConstructorMethod(ctor); } else { return null; } } /** * {@inheritDoc} */ public JexlPropertyGet getPropertyGet(Object obj, Object identifier, JexlInfo info) { JexlPropertyGet get = getGetExecutor(obj, identifier); if (get == null && obj != null && identifier != null) { get = getIndexedGet(obj, identifier.toString()); if (get == null) { Field field = getField(obj, identifier.toString(), info); if (field != null) { return new FieldPropertyGet(field); } } } return get; } /** * {@inheritDoc} */ public JexlPropertySet getPropertySet(final Object obj, final Object identifier, Object arg, JexlInfo info) { JexlPropertySet set = getSetExecutor(obj, identifier, arg); if (set == null && obj != null && identifier != null) { Field field = getField(obj, identifier.toString(), info); if (field != null && !Modifier.isFinal(field.getModifiers()) && (arg == null || MethodKey.isInvocationConvertible(field.getType(), arg.getClass(), false))) { return new FieldPropertySet(field); } } return set; } /** * Returns a class field. * Only for use by sub-classes, will be made protected in a later version * @param obj the object * @param name the field name * @param info debug info * @return a {@link Field}. */ public Field getField(Object obj, String name, JexlInfo info) { final Class clazz = obj instanceof Class ? (Class) obj : obj.getClass(); return getField(clazz, name); } /** * Attempts to find an indexed-property getter in an object. * The code attempts to find the list of methods getXXX() and setXXX(). * Note that this is not equivalent to the strict bean definition of indexed properties; the type of the key * is not necessarily an int and the set/get arrays are not resolved. * @param object the object * @param name the container name * @return a JexlPropertyGet is successfull, null otherwise * @since 2.1 */ protected JexlPropertyGet getIndexedGet(Object object, String name) { if (object != null && name != null) { String base = name.substring(0, 1).toUpperCase() + name.substring(1); final String container = name; final Class clazz = object.getClass(); final Method[] getters = getMethods(object.getClass(), "get" + base); final Method[] setters = getMethods(object.getClass(), "set" + base); if (getters != null) { return new IndexedType(container, clazz, getters, setters); } } return null; } /** * Abstract an indexed property container. * This stores the container name and owning class as well as the list of available getter and setter methods. * It implements JexlPropertyGet since such a container can only be accessed from its owning instance (not set). * @since 2.1 */ private static final class IndexedType implements JexlPropertyGet { /** The container name. */ private final String container; /** The owning class. */ private final Class clazz; /** The array of getter methods. */ private final Method[] getters; /** The array of setter methods. */ private final Method[] setters; /** * Creates a new indexed type. * @param name the container name * @param c the owning class * @param gets the array of getter methods * @param sets the array of setter methods */ IndexedType(String name, Class c, Method[] gets, Method[] sets) { this.container = name; this.clazz = c; this.getters = gets; this.setters = sets; } /** * {@inheritDoc} */ public Object invoke(Object obj) throws Exception { if (obj != null && clazz.equals(obj.getClass())) { return new IndexedContainer(this, obj); } else { throw new IntrospectionException("property resolution error"); } } /** * {@inheritDoc} */ public Object tryInvoke(Object obj, Object key) { if (obj != null && key != null && clazz.equals(obj.getClass()) && container.equals(key.toString())) { return new IndexedContainer(this, obj); } else { return TRY_FAILED; } } /** * {@inheritDoc} */ public boolean tryFailed(Object rval) { return rval == TRY_FAILED; } /** * {@inheritDoc} */ public boolean isCacheable() { return true; } /** * Gets the value of a property from a container. * @param object the instance owning the container (not null) * @param key the property key (not null) * @return the property value * @throws Exception if invocation failed; IntrospectionException if a property getter could not be found */ private Object invokeGet(Object object, Object key) throws Exception { if (getters != null) { final Object[] args = {key}; final Method jm; if (getters.length == 1) { jm = getters[0]; } else { jm = new MethodKey(getters[0].getName(), args).getMostSpecificMethod(Arrays.asList(getters)); } if (jm != null) { return jm.invoke(object, args); } } throw new IntrospectionException("property get error: " + object.getClass().toString() + "@" + key.toString()); } /** * Sets the value of a property in a container. * @param object the instance owning the container (not null) * @param key the property key (not null) * @param value the property value (not null) * @return the result of the method invocation (frequently null) * @throws Exception if invocation failed; IntrospectionException if a property setter could not be found */ private Object invokeSet(Object object, Object key, Object value) throws Exception { if (setters != null) { final Object[] args = {key, value}; final Method jm; if (setters.length == 1) { jm = setters[0]; } else { jm = new MethodKey(setters[0].getName(), args).getMostSpecificMethod(Arrays.asList(setters)); } if (jm != null) { return jm.invoke(object, args); } } throw new IntrospectionException("property set error: " + object.getClass().toString() + "@" + key.toString()); } } /** * A generic indexed property container, exposes get(key) and set(key, value) and solves method call dynamically * based on arguments. * @since 2.1 */ public static final class IndexedContainer { /** The instance owning the container. */ private final Object object; /** The container type instance. */ private final IndexedType type; /** * Creates a new duck container. * @param theType the container type * @param theObject the instance owning the container */ private IndexedContainer(IndexedType theType, Object theObject) { this.type = theType; this.object = theObject; } /** * Gets a property from a container. * @param key the property key * @return the property value * @throws Exception if inner invocation fails */ public Object get(Object key) throws Exception { return type.invokeGet(object, key); } /** * Sets a property in a container. * @param key the property key * @param value the property value * @return the invocation result (frequently null) * @throws Exception if inner invocation fails */ public Object set(Object key, Object value) throws Exception { return type.invokeSet(object, key, value); } } /** * A JexlMethod that wraps constructor. * @since 2.1 */ private final class ConstructorMethod implements JexlMethod { /** The wrapped constructor. */ private final Constructor ctor; /** * Creates a constructor method. * @param theCtor the constructor to wrap */ private ConstructorMethod(Constructor theCtor) { this.ctor = theCtor; } /** * {@inheritDoc} */ public Object invoke(Object obj, Object[] params) throws Exception { Class clazz = null; if (obj instanceof Class) { clazz = (Class) obj; } else if (obj != null) { clazz = getClassByName(obj.toString()); } else { clazz = ctor.getDeclaringClass(); } if (clazz.equals(ctor.getDeclaringClass())) { return ctor.newInstance(params); } else { throw new IntrospectionException("constructor resolution error"); } } /** * {@inheritDoc} */ public Object tryInvoke(String name, Object obj, Object[] params) { Class clazz = null; if (obj instanceof Class) { clazz = (Class) obj; } else if (obj != null) { clazz = getClassByName(obj.toString()); } else { clazz = ctor.getDeclaringClass(); } if (clazz.equals(ctor.getDeclaringClass()) && (name == null || name.equals(clazz.getName()))) { try { return ctor.newInstance(params); } catch (InstantiationException xinstance) { return TRY_FAILED; } catch (IllegalAccessException xaccess) { return TRY_FAILED; } catch (IllegalArgumentException xargument) { return TRY_FAILED; } catch (InvocationTargetException xinvoke) { return TRY_FAILED; } } return TRY_FAILED; } /** * {@inheritDoc} */ public boolean tryFailed(Object rval) { return rval == TRY_FAILED; } /** * {@inheritDoc} */ public boolean isCacheable() { return true; } /** * {@inheritDoc} */ public Class getReturnType() { return ctor.getDeclaringClass(); } } /** * A JexlPropertyGet for public fields. * @deprecated Do not use externally - will be made private in a later version */ @Deprecated public static final class FieldPropertyGet implements JexlPropertyGet { /** * The public field. */ private final Field field; /** * Creates a new instance of FieldPropertyGet. * @param theField the class public field */ public FieldPropertyGet(Field theField) { field = theField; } /** * {@inheritDoc} */ public Object invoke(Object obj) throws Exception { return field.get(obj); } /** * {@inheritDoc} */ public Object tryInvoke(Object obj, Object key) { if (obj.getClass().equals(field.getDeclaringClass()) && key.equals(field.getName())) { try { return field.get(obj); } catch (IllegalAccessException xill) { return TRY_FAILED; } } return TRY_FAILED; } /** * {@inheritDoc} */ public boolean tryFailed(Object rval) { return rval == TRY_FAILED; } /** * {@inheritDoc} */ public boolean isCacheable() { return true; } } /** * A JexlPropertySet for public fields. * @deprecated Do not use externally - will be made private in a later version */ @Deprecated public static final class FieldPropertySet implements JexlPropertySet { /** * The public field. */ private final Field field; /** * Creates a new instance of FieldPropertySet. * @param theField the class public field */ public FieldPropertySet(Field theField) { field = theField; } /** * {@inheritDoc} */ public Object invoke(Object obj, Object arg) throws Exception { field.set(obj, arg); return arg; } /** * {@inheritDoc} */ public Object tryInvoke(Object obj, Object key, Object value) { if (obj.getClass().equals(field.getDeclaringClass()) && key.equals(field.getName()) && (value == null || MethodKey.isInvocationConvertible(field.getType(), value.getClass(), false))) { try { field.set(obj, value); return value; } catch (IllegalAccessException xill) { return TRY_FAILED; } } return TRY_FAILED; } /** * {@inheritDoc} */ public boolean tryFailed(Object rval) { return rval == TRY_FAILED; } /** * {@inheritDoc} */ public boolean isCacheable() { return true; } } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/JexlArithmetic.java100644 0 0 123047 11673634323 25043 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.BigInteger; import java.math.MathContext; /** * Perform arithmetic. *

* All arithmetic operators (+, - , *, /, %) follow the same rules regarding their arguments. *

    *
  1. If both are null, result is 0
  2. *
  3. If either is a BigDecimal, coerce both to BigDecimal and and perform operation
  4. *
  5. If either is a floating point number, coerce both to Double and perform operation
  6. *
  7. If both are BigInteger, treat as BigInteger and perform operation
  8. *
  9. Else treat as BigInteger, perform operation and attempt to narrow result: *
      *
    1. if both arguments can be narrowed to Integer, narrow result to Integer
    2. *
    3. if both arguments can be narrowed to Long, narrow result to Long
    4. *
    5. Else return result as BigInteger
    6. *
    *
  10. *
*

* Note that the only exception throw by JexlArithmetic is ArithmeticException. * @since 2.0 */ public class JexlArithmetic { /** Double.MAX_VALUE as BigDecimal. */ protected static final BigDecimal BIGD_DOUBLE_MAX_VALUE = BigDecimal.valueOf(Double.MAX_VALUE); /** Double.MIN_VALUE as BigDecimal. */ protected static final BigDecimal BIGD_DOUBLE_MIN_VALUE = BigDecimal.valueOf(Double.MIN_VALUE); /** Long.MAX_VALUE as BigInteger. */ protected static final BigInteger BIGI_LONG_MAX_VALUE = BigInteger.valueOf(Long.MAX_VALUE); /** Long.MIN_VALUE as BigInteger. */ protected static final BigInteger BIGI_LONG_MIN_VALUE = BigInteger.valueOf(Long.MIN_VALUE); /** * Default BigDecimal scale. * @since 2.1 */ protected static final int BIGD_SCALE = -1; /** Whether this JexlArithmetic instance behaves in strict or lenient mode. * May be made final in a later version. */ private volatile boolean strict; /** * The big decimal math context. * @since 2.1 */ protected final MathContext mathContext; /** * The big decimal scale. * @since 2.1 */ protected final int mathScale; /** * Creates a JexlArithmetic. * @param lenient whether this arithmetic is lenient or strict */ public JexlArithmetic(boolean lenient) { this(lenient, MathContext.DECIMAL128, BIGD_SCALE); } /** * Creates a JexlArithmetic. * @param lenient whether this arithmetic is lenient or strict * @param bigdContext the math context instance to use for +,-,/,*,% operations on big decimals. * @param bigdScale the scale used for big decimals. * @since 2.1 */ public JexlArithmetic(boolean lenient, MathContext bigdContext, int bigdScale) { this.strict = !lenient; this.mathContext = bigdContext; this.mathScale = bigdScale; } /** * Sets whether this JexlArithmetic instance triggers errors during evaluation when * null is used as an operand. *

This method is not thread safe; it may be called as an optional step by the JexlEngine * in its initialization code before expression creation & evaluation.

* @see JexlEngine#setLenient * @see JexlEngine#setSilent * @see JexlEngine#setDebug * @param flag true means no JexlException will occur, false allows them * @deprecated as of 2.1 - may be removed in a later release */ @Deprecated void setLenient(boolean flag) { this.strict = !flag; } /** * Checks whether this JexlArithmetic instance triggers errors during evaluation * when null is used as an operand. * @return true if lenient, false if strict */ public boolean isLenient() { return !this.strict; } /** * The MathContext instance used for +,-,/,*,% operations on big decimals. * @return the math context * @since 2.1 */ public MathContext getMathContext() { return mathContext; } /** * The BigDecimal scale used for comparison and coercion operations. * @return the scale * @since 2.1 */ public int getMathScale() { return mathScale; } /** * Ensure a big decimal is rounded by this arithmetic scale and rounding mode. * @param number the big decimal to round * @return the rounded big decimal * @since 2.1 */ public BigDecimal roundBigDecimal(final BigDecimal number) { int mscale = getMathScale(); if (mscale >= 0) { return number.setScale(mscale, getMathContext().getRoundingMode()); } else { return number; } } /** * The result of +,/,-,*,% when both operands are null. * @return Integer(0) if lenient * @throws ArithmeticException if strict */ protected Object controlNullNullOperands() { if (!isLenient()) { throw new ArithmeticException(JexlException.NULL_OPERAND); } return Integer.valueOf(0); } /** * Throw a NPE if arithmetic is strict. * @throws ArithmeticException if strict */ protected void controlNullOperand() { if (!isLenient()) { throw new ArithmeticException(JexlException.NULL_OPERAND); } } /** * Test if either left or right are either a Float or Double. * @param left one object to test * @param right the other * @return the result of the test. */ protected boolean isFloatingPointType(Object left, Object right) { return left instanceof Float || left instanceof Double || right instanceof Float || right instanceof Double; } /** * Test if the passed value is a floating point number, i.e. a float, double * or string with ( "." | "E" | "e"). * * @param val the object to be tested * @return true if it is, false otherwise. */ protected boolean isFloatingPointNumber(Object val) { if (val instanceof Float || val instanceof Double) { return true; } if (val instanceof String) { String string = (String) val; return string.indexOf('.') != -1 || string.indexOf('e') != -1 || string.indexOf('E') != -1; } return false; } /** * Is Object a floating point number. * * @param o Object to be analyzed. * @return true if it is a Float or a Double. */ protected boolean isFloatingPoint(final Object o) { return o instanceof Float || o instanceof Double; } /** * Is Object a whole number. * * @param o Object to be analyzed. * @return true if Integer, Long, Byte, Short or Character. */ protected boolean isNumberable(final Object o) { return o instanceof Integer || o instanceof Long || o instanceof Byte || o instanceof Short || o instanceof Character; } /** * Given a BigInteger, narrow it to an Integer or Long if it fits and the arguments * class allow it. *

* The rules are: * if either arguments is a BigInteger, no narrowing will occur * if either arguments is a Long, no narrowing to Integer will occur *

* @param lhs the left hand side operand that lead to the bigi result * @param rhs the right hand side operand that lead to the bigi result * @param bigi the BigInteger to narrow * @return an Integer or Long if narrowing is possible, the original BigInteger otherwise */ protected Number narrowBigInteger(Object lhs, Object rhs, BigInteger bigi) { //coerce to long if possible if (!(lhs instanceof BigInteger || rhs instanceof BigInteger) && bigi.compareTo(BIGI_LONG_MAX_VALUE) <= 0 && bigi.compareTo(BIGI_LONG_MIN_VALUE) >= 0) { // coerce to int if possible long l = bigi.longValue(); // coerce to int when possible (int being so often used in method parms) if (!(lhs instanceof Long || rhs instanceof Long) && l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) { return Integer.valueOf((int) l); } return Long.valueOf(l); } return bigi; } /** * Given a BigDecimal, attempt to narrow it to an Integer or Long if it fits if * one of the arguments is a numberable. * * @param lhs the left hand side operand that lead to the bigd result * @param rhs the right hand side operand that lead to the bigd result * @param bigd the BigDecimal to narrow * @return an Integer or Long if narrowing is possible, the original BigInteger otherwise * @since 2.1 */ protected Number narrowBigDecimal(Object lhs, Object rhs, BigDecimal bigd) { if (isNumberable(lhs) || isNumberable(rhs)) { try { long l = bigd.longValueExact(); // coerce to int when possible (int being so often used in method parms) if (l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) { return Integer.valueOf((int) l); } else { return Long.valueOf(l); } } catch (ArithmeticException xa) { // ignore, no exact value possible } } return bigd; } /** * Given an array of objects, attempt to type it more strictly. *
    *
  • If all objects are of the same type, the array returned will be an array of that same type
  • *
  • If all objects are Numbers, the array returned will be an array of Numbers
  • *
  • If all objects are convertible to a primitive type, the array returned will be an array * of the primitive type
  • *
* @param untyped an untyped array * @return the original array if the attempt to strictly type the array fails, a typed array otherwise */ protected Object narrowArrayType(Object[] untyped) { final int size = untyped.length; Class commonClass = null; if (size > 0) { boolean isNumber = true; // for all children after first... for (int u = 0; u < size && !Object.class.equals(commonClass); ++u) { if (untyped[u] != null) { Class eclass = untyped[u].getClass(); // base common class on first non-null entry if (commonClass == null) { commonClass = eclass; isNumber &= Number.class.isAssignableFrom(commonClass); } else if (!commonClass.equals(eclass)) { // if both are numbers... if (isNumber && Number.class.isAssignableFrom(eclass)) { commonClass = Number.class; } else { // attempt to find valid superclass do { eclass = eclass.getSuperclass(); if (eclass == null) { commonClass = Object.class; break; } } while (!commonClass.isAssignableFrom(eclass)); } } } else { isNumber = false; } } // convert array to the common class if not Object.class if (commonClass != null && !Object.class.equals(commonClass)) { // if the commonClass has an equivalent primitive type, get it if (isNumber) { try { final Field type = commonClass.getField("TYPE"); commonClass = (Class) type.get(null); } catch (Exception xany) { // ignore } } // allocate and fill up the typed array Object typed = Array.newInstance(commonClass, size); for (int i = 0; i < size; ++i) { Array.set(typed, i, untyped[i]); } return typed; } } return untyped; } /** * Replace all numbers in an arguments array with the smallest type that will fit. * @param args the argument array * @return true if some arguments were narrowed and args array is modified, * false if no narrowing occured and args array has not been modified */ protected boolean narrowArguments(Object[] args) { boolean narrowed = false; for (int a = 0; a < args.length; ++a) { Object arg = args[a]; if (arg instanceof Number) { Object narg = narrow((Number) arg); if (narg != arg) { narrowed = true; } args[a] = narg; } } return narrowed; } /** * Add two values together. *

* If any numeric add fails on coercion to the appropriate type, * treat as Strings and do concatenation. *

* @param left first value * @param right second value * @return left + right. */ public Object add(Object left, Object right) { if (left == null && right == null) { return controlNullNullOperands(); } try { // if either are floating point (double or float) use double if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { double l = toDouble(left); double r = toDouble(right); return new Double(l + r); } // if either are bigdecimal use that type if (left instanceof BigDecimal || right instanceof BigDecimal) { BigDecimal l = toBigDecimal(left); BigDecimal r = toBigDecimal(right); BigDecimal result = l.add(r, getMathContext()); return narrowBigDecimal(left, right, result); } // otherwise treat as integers BigInteger l = toBigInteger(left); BigInteger r = toBigInteger(right); BigInteger result = l.add(r); return narrowBigInteger(left, right, result); } catch (java.lang.NumberFormatException nfe) { // Well, use strings! return toString(left).concat(toString(right)); } } /** * Divide the left value by the right. * @param left first value * @param right second value * @return left / right * @throws ArithmeticException if right == 0 */ public Object divide(Object left, Object right) { if (left == null && right == null) { return controlNullNullOperands(); } // if either are floating point (double or float) use double if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { double l = toDouble(left); double r = toDouble(right); if (r == 0.0) { throw new ArithmeticException("/"); } return new Double(l / r); } // if either are bigdecimal use that type if (left instanceof BigDecimal || right instanceof BigDecimal) { BigDecimal l = toBigDecimal(left); BigDecimal r = toBigDecimal(right); if (BigDecimal.ZERO.equals(r)) { throw new ArithmeticException("/"); } BigDecimal result = l.divide(r, getMathContext()); return narrowBigDecimal(left, right, result); } // otherwise treat as integers BigInteger l = toBigInteger(left); BigInteger r = toBigInteger(right); if (BigInteger.ZERO.equals(r)) { throw new ArithmeticException("/"); } BigInteger result = l.divide(r); return narrowBigInteger(left, right, result); } /** * left value mod right. * @param left first value * @param right second value * @return left mod right * @throws ArithmeticException if right == 0.0 */ public Object mod(Object left, Object right) { if (left == null && right == null) { return controlNullNullOperands(); } // if either are floating point (double or float) use double if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { double l = toDouble(left); double r = toDouble(right); if (r == 0.0) { throw new ArithmeticException("%"); } return new Double(l % r); } // if either are bigdecimal use that type if (left instanceof BigDecimal || right instanceof BigDecimal) { BigDecimal l = toBigDecimal(left); BigDecimal r = toBigDecimal(right); if (BigDecimal.ZERO.equals(r)) { throw new ArithmeticException("%"); } BigDecimal remainder = l.remainder(r, getMathContext()); return narrowBigDecimal(left, right, remainder); } // otherwise treat as integers BigInteger l = toBigInteger(left); BigInteger r = toBigInteger(right); BigInteger result = l.mod(r); if (BigInteger.ZERO.equals(r)) { throw new ArithmeticException("%"); } return narrowBigInteger(left, right, result); } /** * Multiply the left value by the right. * @param left first value * @param right second value * @return left * right. */ public Object multiply(Object left, Object right) { if (left == null && right == null) { return controlNullNullOperands(); } // if either are floating point (double or float) use double if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { double l = toDouble(left); double r = toDouble(right); return new Double(l * r); } // if either are bigdecimal use that type if (left instanceof BigDecimal || right instanceof BigDecimal) { BigDecimal l = toBigDecimal(left); BigDecimal r = toBigDecimal(right); BigDecimal result = l.multiply(r, getMathContext()); return narrowBigDecimal(left, right, result); } // otherwise treat as integers BigInteger l = toBigInteger(left); BigInteger r = toBigInteger(right); BigInteger result = l.multiply(r); return narrowBigInteger(left, right, result); } /** * Subtract the right value from the left. * @param left first value * @param right second value * @return left - right. */ public Object subtract(Object left, Object right) { if (left == null && right == null) { return controlNullNullOperands(); } // if either are floating point (double or float) use double if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { double l = toDouble(left); double r = toDouble(right); return new Double(l - r); } // if either are bigdecimal use that type if (left instanceof BigDecimal || right instanceof BigDecimal) { BigDecimal l = toBigDecimal(left); BigDecimal r = toBigDecimal(right); BigDecimal result = l.subtract(r, getMathContext()); return narrowBigDecimal(left, right, result); } // otherwise treat as integers BigInteger l = toBigInteger(left); BigInteger r = toBigInteger(right); BigInteger result = l.subtract(r); return narrowBigInteger(left, right, result); } /** * Negates a value (unary minus for numbers). * @param val the value to negate * @return the negated value * @since 2.1 */ public Object negate(Object val) { if (val instanceof Integer) { int valueAsInt = ((Integer) val).intValue(); return Integer.valueOf(-valueAsInt); } else if (val instanceof Double) { double valueAsDouble = ((Double) val).doubleValue(); return new Double(-valueAsDouble); } else if (val instanceof Long) { long valueAsLong = -((Long) val).longValue(); return Long.valueOf(valueAsLong); } else if (val instanceof BigDecimal) { BigDecimal valueAsBigD = (BigDecimal) val; return valueAsBigD.negate(); } else if (val instanceof BigInteger) { BigInteger valueAsBigI = (BigInteger) val; return valueAsBigI.negate(); } else if (val instanceof Float) { float valueAsFloat = ((Float) val).floatValue(); return new Float(-valueAsFloat); } else if (val instanceof Short) { short valueAsShort = ((Short) val).shortValue(); return Short.valueOf((short) -valueAsShort); } else if (val instanceof Byte) { byte valueAsByte = ((Byte) val).byteValue(); return Byte.valueOf((byte) -valueAsByte); } else if (val instanceof Boolean) { return ((Boolean) val).booleanValue() ? Boolean.FALSE : Boolean.TRUE; } throw new ArithmeticException("Object negation:(" + val + ")"); } /** * Test if left regexp matches right. * * @param left first value * @param right second value * @return test result. * @since 2.1 */ public boolean matches(Object left, Object right) { if (left == null && right == null) { //if both are null L == R return true; } if (left == null || right == null) { // we know both aren't null, therefore L != R return false; } final String arg = left.toString(); if (right instanceof java.util.regex.Pattern) { return ((java.util.regex.Pattern) right).matcher(arg).matches(); } else { return arg.matches(right.toString()); } } /** * Performs a bitwise and. * @param left the left operand * @param right the right operator * @return left & right * @since 2.1 */ public Object bitwiseAnd(Object left, Object right) { long l = toLong(left); long r = toLong(right); return Long.valueOf(l & r); } /** * Performs a bitwise or. * @param left the left operand * @param right the right operator * @return left | right * @since 2.1 */ public Object bitwiseOr(Object left, Object right) { long l = toLong(left); long r = toLong(right); return Long.valueOf(l | r); } /** * Performs a bitwise xor. * @param left the left operand * @param right the right operator * @return left right * @since 2.1 */ public Object bitwiseXor(Object left, Object right) { long l = toLong(left); long r = toLong(right); return Long.valueOf(l ^ r); } /** * Performs a bitwise complement. * @param val the operand * @return ~val * @since 2.1 */ public Object bitwiseComplement(Object val) { long l = toLong(val); return Long.valueOf(~l); } /** * Performs a comparison. * @param left the left operand * @param right the right operator * @param operator the operator * @return -1 if left < right; +1 if left > > right; 0 if left == right * @throws ArithmeticException if either left or right is null * @since 2.1 */ protected int compare(Object left, Object right, String operator) { if (left != null && right != null) { if (left instanceof BigDecimal || right instanceof BigDecimal) { BigDecimal l = toBigDecimal(left); BigDecimal r = toBigDecimal(right); return l.compareTo(r); } else if (left instanceof BigInteger || right instanceof BigInteger) { BigInteger l = toBigInteger(left); BigInteger r = toBigInteger(right); return l.compareTo(r); } else if (isFloatingPoint(left) || isFloatingPoint(right)) { double lhs = toDouble(left); double rhs = toDouble(right); if (Double.isNaN(lhs)) { if (Double.isNaN(rhs)) { return 0; } else { return -1; } } else if (Double.isNaN(rhs)) { // lhs is not NaN return +1; } else if (lhs < rhs) { return -1; } else if (lhs > rhs) { return +1; } else { return 0; } } else if (isNumberable(left) || isNumberable(right)) { long lhs = toLong(left); long rhs = toLong(right); if (lhs < rhs) { return -1; } else if (lhs > rhs) { return +1; } else { return 0; } } else if (left instanceof String || right instanceof String) { return toString(left).compareTo(toString(right)); } else if ("==".equals(operator)) { return left.equals(right) ? 0 : -1; } else if (left instanceof Comparable) { @SuppressWarnings("unchecked") // OK because of instanceof check above final Comparable comparable = (Comparable) left; return comparable.compareTo(right); } else if (right instanceof Comparable) { @SuppressWarnings("unchecked") // OK because of instanceof check above final Comparable comparable = (Comparable) right; return comparable.compareTo(left); } } throw new ArithmeticException("Object comparison:(" + left + " " + operator + " " + right + ")"); } /** * Test if left and right are equal. * * @param left first value * @param right second value * @return test result. */ public boolean equals(Object left, Object right) { if (left == right) { return true; } else if (left == null || right == null) { return false; } else if (left instanceof Boolean || right instanceof Boolean) { return toBoolean(left) == toBoolean(right); } else { return compare(left, right, "==") == 0; } } /** * Test if left < right. * * @param left first value * @param right second value * @return test result. */ public boolean lessThan(Object left, Object right) { if ((left == right) || (left == null) || (right == null)) { return false; } else { return compare(left, right, "<") < 0; } } /** * Test if left > right. * * @param left first value * @param right second value * @return test result. */ public boolean greaterThan(Object left, Object right) { if ((left == right) || left == null || right == null) { return false; } else { return compare(left, right, ">") > 0; } } /** * Test if left <= right. * * @param left first value * @param right second value * @return test result. */ public boolean lessThanOrEqual(Object left, Object right) { if (left == right) { return true; } else if (left == null || right == null) { return false; } else { return compare(left, right, "<=") <= 0; } } /** * Test if left >= right. * * @param left first value * @param right second value * @return test result. */ public boolean greaterThanOrEqual(Object left, Object right) { if (left == right) { return true; } else if (left == null || right == null) { return false; } else { return compare(left, right, ">=") >= 0; } } /** * Coerce to a boolean (not a java.lang.Boolean). * * @param val Object to be coerced. * @return The boolean coerced value, or false if none possible. */ public boolean toBoolean(Object val) { if (val == null) { controlNullOperand(); return false; } else if (val instanceof Boolean) { return ((Boolean) val).booleanValue(); } else if (val instanceof Number) { double number = toDouble(val); return !Double.isNaN(number) && number != 0.d; } else if (val instanceof String) { String strval = val.toString(); return strval.length() > 0 && !"false".equals(strval); } // TODO: is this a reasonable default? return false; } /** * Coerce to a int. * * @param val Object to be coerced. * @return The int coerced value. */ public int toInteger(Object val) { if (val == null) { controlNullOperand(); return 0; } else if (val instanceof Double) { if (!Double.isNaN(((Double) val).doubleValue())) { return 0; } else { return ((Double) val).intValue(); } } else if (val instanceof Number) { return ((Number) val).intValue(); } else if (val instanceof String) { if ("".equals(val)) { return 0; } return Integer.parseInt((String) val); } else if (val instanceof Boolean) { return ((Boolean) val).booleanValue() ? 1 : 0; } else if (val instanceof Character) { return ((Character) val).charValue(); } throw new ArithmeticException("Integer coercion: " + val.getClass().getName() + ":(" + val + ")"); } /** * Coerce to a long (not a java.lang.Long). * * @param val Object to be coerced. * @return The long coerced value. */ public long toLong(Object val) { if (val == null) { controlNullOperand(); return 0L; } else if (val instanceof Double) { if (!Double.isNaN(((Double) val).doubleValue())) { return 0; } else { return ((Double) val).longValue(); } } else if (val instanceof Number) { return ((Number) val).longValue(); } else if (val instanceof String) { if ("".equals(val)) { return 0; } else { return Long.parseLong((String) val); } } else if (val instanceof Boolean) { return ((Boolean) val).booleanValue() ? 1L : 0L; } else if (val instanceof Character) { return ((Character) val).charValue(); } throw new ArithmeticException("Long coercion: " + val.getClass().getName() + ":(" + val + ")"); } /** * Get a BigInteger from the object passed. * Null and empty string maps to zero. * @param val the object to be coerced. * @return a BigDecimal. * @throws NullPointerException if val is null and mode is strict. */ public BigInteger toBigInteger(Object val) { if (val == null) { controlNullOperand(); return BigInteger.ZERO; } else if (val instanceof BigInteger) { return (BigInteger) val; } else if (val instanceof Double) { if (!Double.isNaN(((Double) val).doubleValue())) { return new BigInteger(val.toString()); } else { return BigInteger.ZERO; } } else if (val instanceof Number) { return new BigInteger(val.toString()); } else if (val instanceof String) { String string = (String) val; if ("".equals(string.trim())) { return BigInteger.ZERO; } else { return new BigInteger(string); } } else if (val instanceof Character) { int i = ((Character) val).charValue(); return BigInteger.valueOf(i); } throw new ArithmeticException("BigInteger coercion: " + val.getClass().getName() + ":(" + val + ")"); } /** * Get a BigDecimal from the object passed. * Null and empty string maps to zero. * @param val the object to be coerced. * @return a BigDecimal. * @throws NullPointerException if val is null and mode is strict. */ public BigDecimal toBigDecimal(Object val) { if (val instanceof BigDecimal) { return roundBigDecimal((BigDecimal) val); } else if (val == null) { controlNullOperand(); return BigDecimal.ZERO; } else if (val instanceof String) { String string = ((String) val).trim(); if ("".equals(string)) { return BigDecimal.ZERO; } return roundBigDecimal(new BigDecimal(string, getMathContext())); } else if (val instanceof Double) { if (!Double.isNaN(((Double) val).doubleValue())) { return roundBigDecimal(new BigDecimal(val.toString(), getMathContext())); } else { return BigDecimal.ZERO; } } else if (val instanceof Number) { return roundBigDecimal(new BigDecimal(val.toString(), getMathContext())); } else if (val instanceof Character) { int i = ((Character) val).charValue(); return new BigDecimal(i); } throw new ArithmeticException("BigDecimal coercion: " + val.getClass().getName() + ":(" + val + ")"); } /** * Coerce to a double. * * @param val Object to be coerced. * @return The double coerced value. * @throws NullPointerException if val is null and mode is strict. */ public double toDouble(Object val) { if (val == null) { controlNullOperand(); return 0; } else if (val instanceof Double) { return ((Double) val).doubleValue(); } else if (val instanceof Number) { //The below construct is used rather than ((Number)val).doubleValue() to ensure //equality between comparing new Double( 6.4 / 3 ) and the jexl expression of 6.4 / 3 return Double.parseDouble(String.valueOf(val)); } else if (val instanceof Boolean) { return ((Boolean) val).booleanValue() ? 1. : 0.; } else if (val instanceof String) { String string = ((String) val).trim(); if ("".equals(string)) { return Double.NaN; } else { // the spec seems to be iffy about this. Going to give it a wack anyway return Double.parseDouble(string); } } else if (val instanceof Character) { int i = ((Character) val).charValue(); return i; } throw new ArithmeticException("Double coercion: " + val.getClass().getName() + ":(" + val + ")"); } /** * Coerce to a string. * * @param val Object to be coerced. * @return The String coerced value. * @throws NullPointerException if val is null and mode is strict. */ public String toString(Object val) { if (val == null) { controlNullOperand(); return ""; } else if (val instanceof Double) { Double dval = (Double) val; if (Double.isNaN(dval.doubleValue())) { return ""; } else { return dval.toString(); } } else { return val.toString(); } } /** * Given a Number, return back the value using the smallest type the result * will fit into. This works hand in hand with parameter 'widening' in java * method calls, e.g. a call to substring(int,int) with an int and a long * will fail, but a call to substring(int,int) with an int and a short will * succeed. * * @param original the original number. * @return a value of the smallest type the original number will fit into. */ public Number narrow(Number original) { return narrowNumber(original, null); } /** * Whether we consider the narrow class as a potential candidate for narrowing the source. * @param narrow the target narrow class * @param source the orginal source class * @return true if attempt to narrow source to target is accepted * @since 2.1 */ protected boolean narrowAccept(Class narrow, Class source) { return narrow == null || narrow.equals(source); } /** * Given a Number, return back the value attempting to narrow it to a target class. * @param original the original number * @param narrow the attempted target class * @return the narrowed number or the source if no narrowing was possible * @since 2.1 */ protected Number narrowNumber(Number original, Class narrow) { if (original == null) { return original; } Number result = original; if (original instanceof BigDecimal) { BigDecimal bigd = (BigDecimal) original; // if it's bigger than a double it can't be narrowed if (bigd.compareTo(BIGD_DOUBLE_MAX_VALUE) > 0) { return original; } else { try { long l = bigd.longValueExact(); // coerce to int when possible (int being so often used in method parms) if (narrowAccept(narrow, Integer.class) && l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) { return Integer.valueOf((int) l); } else if (narrowAccept(narrow, Long.class)) { return Long.valueOf(l); } } catch (ArithmeticException xa) { // ignore, no exact value possible } } } if (original instanceof Double || original instanceof Float || original instanceof BigDecimal) { double value = original.doubleValue(); if (narrowAccept(narrow, Float.class) && value <= Float.MAX_VALUE && value >= Float.MIN_VALUE) { result = Float.valueOf(result.floatValue()); } // else it fits in a double only } else { if (original instanceof BigInteger) { BigInteger bigi = (BigInteger) original; // if it's bigger than a Long it can't be narrowed if (bigi.compareTo(BIGI_LONG_MAX_VALUE) > 0 || bigi.compareTo(BIGI_LONG_MIN_VALUE) < 0) { return original; } } long value = original.longValue(); if (narrowAccept(narrow, Byte.class) && value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) { // it will fit in a byte result = Byte.valueOf((byte) value); } else if (narrowAccept(narrow, Short.class) && value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) { result = Short.valueOf((short) value); } else if (narrowAccept(narrow, Integer.class) && value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) { result = Integer.valueOf((int) value); } // else it fits in a long } return result; } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/JexlContext.java100644 0 0 3610 11673634322 24326 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Manages variables which can be referenced in a JEXL expression. *

Note that JEXL may use '$jexl' and '$ujexl' variables for internal purpose; setting or getting those * variables may lead to unexpected results unless specified otherwise.

* @since 1.0 * @version $Id: JexlContext.java 1202769 2011-11-16 16:33:02Z henrib $ */ public interface JexlContext { /** * Gets the value of a variable. * @param name the variable's name * @return the value */ Object get(String name); /** * Sets the value of a variable. * @param name the variable's name * @param value the variable's value */ void set(String name, Object value); /** * Checks whether a variable is defined in this context. *

A variable may be defined with a null value; this method checks whether the * value is null or if the variable is undefined.

* @param name the variable's name * @return true if it exists, false otherwise */ boolean has(String name); } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/JexlEngine.java100644 0 0 146444 11673634324 24166 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; import java.io.Reader; import java.net.URL; import java.net.URLConnection; import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.Map; import java.util.Set; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map.Entry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.jexl2.parser.ParseException; import org.apache.commons.jexl2.parser.Parser; import org.apache.commons.jexl2.parser.JexlNode; import org.apache.commons.jexl2.parser.TokenMgrError; import org.apache.commons.jexl2.parser.ASTJexlScript; import org.apache.commons.jexl2.introspection.Uberspect; import org.apache.commons.jexl2.introspection.UberspectImpl; import org.apache.commons.jexl2.introspection.JexlMethod; import org.apache.commons.jexl2.parser.ASTArrayAccess; import org.apache.commons.jexl2.parser.ASTIdentifier; import org.apache.commons.jexl2.parser.ASTReference; /** *

* Creates and evaluates Expression and Script objects. * Determines the behavior of Expressions & Scripts during their evaluation with respect to: *

    *
  • Introspection, see {@link Uberspect}
  • *
  • Arithmetic & comparison, see {@link JexlArithmetic}
  • *
  • Error reporting
  • *
  • Logging
  • *
*

*

The setSilent and setLenient methods allow to fine-tune an engine instance behavior * according to various error control needs. The lenient/strict flag tells the engine when and if null as operand is * considered an error, the silent/verbose flag tells the engine what to do with the error * (log as warning or throw exception). *

*
    *
  • When "silent" & "lenient": *

    0 & null should be indicators of "default" values so that even in an case of error, * something meaningfull can still be inferred; may be convenient for configurations. *

    *
  • *
  • When "silent" & "strict": *

    One should probably consider using null as an error case - ie, every object * manipulated by JEXL should be valued; the ternary operator, especially the '?:' form * can be used to workaround exceptional cases. * Use case could be configuration with no implicit values or defaults. *

    *
  • *
  • When "verbose" & "lenient": *

    The error control grain is roughly on par with JEXL 1.0

    *
  • *
  • When "verbose" & "strict": *

    The finest error control grain is obtained; it is the closest to Java code - * still augmented by "script" capabilities regarding automated conversions & type matching. *

    *
  • *
*

* Note that methods that evaluate expressions may throw unchecked exceptions; * The {@link JexlException} are thrown in "non-silent" mode but since these are * RuntimeException, user-code should catch them wherever most appropriate. *

* @since 2.0 */ public class JexlEngine { /** * An empty/static/non-mutable JexlContext used instead of null context. */ public static final JexlContext EMPTY_CONTEXT = new JexlContext() { /** {@inheritDoc} */ public Object get(String name) { return null; } /** {@inheritDoc} */ public boolean has(String name) { return false; } /** {@inheritDoc} */ public void set(String name, Object value) { throw new UnsupportedOperationException("Not supported in void context."); } }; /** * Gets the default instance of Uberspect. *

This is lazily initialized to avoid building a default instance if there * is no use for it. The main reason for not using the default Uberspect instance is to * be able to use a (low level) introspector created with a given logger * instead of the default one.

*

Implemented as on demand holder idiom.

*/ private static final class UberspectHolder { /** The default uberspector that handles all introspection patterns. */ private static final Uberspect UBERSPECT = new UberspectImpl(LogFactory.getLog(JexlEngine.class)); /** Non-instantiable. */ private UberspectHolder() { } } /** * The Uberspect instance. */ protected final Uberspect uberspect; /** * The JexlArithmetic instance. */ protected final JexlArithmetic arithmetic; /** * The Log to which all JexlEngine messages will be logged. */ protected final Log logger; /** * The singleton ExpressionFactory also holds a single instance of * {@link Parser}. * When parsing expressions, ExpressionFactory synchronizes on Parser. */ protected final Parser parser = new Parser(new StringReader(";")); //$NON-NLS-1$ /** * Whether expressions evaluated by this engine will throw exceptions (false) or * return null (true) on errors. Default is false. */ // TODO could this be private? protected volatile boolean silent = false; /** * Whether error messages will carry debugging information. */ // TODO could this be private? protected volatile boolean debug = true; /** * The map of 'prefix:function' to object implementing the functions. */ // TODO this could probably be private; is it threadsafe? protected Map functions = Collections.emptyMap(); /** * The expression cache. */ // TODO is this thread-safe? Could it be made private? protected SoftCache cache = null; /** * The default cache load factor. */ private static final float LOAD_FACTOR = 0.75f; /** * Creates an engine with default arguments. */ public JexlEngine() { this(null, null, null, null); } /** * Creates a JEXL engine using the provided {@link Uberspect}, (@link JexlArithmetic), * a function map and logger. * @param anUberspect to allow different introspection behaviour * @param anArithmetic to allow different arithmetic behaviour * @param theFunctions an optional map of functions (@link setFunctions) * @param log the logger for various messages */ public JexlEngine(Uberspect anUberspect, JexlArithmetic anArithmetic, Map theFunctions, Log log) { this.uberspect = anUberspect == null ? getUberspect(log) : anUberspect; if (log == null) { log = LogFactory.getLog(JexlEngine.class); } this.logger = log; this.arithmetic = anArithmetic == null ? new JexlArithmetic(true) : anArithmetic; if (theFunctions != null) { this.functions = theFunctions; } } /** * Gets the default instance of Uberspect. *

This is lazily initialized to avoid building a default instance if there * is no use for it. The main reason for not using the default Uberspect instance is to * be able to use a (low level) introspector created with a given logger * instead of the default one.

* @param logger the logger to use for the underlying Uberspect * @return Uberspect the default uberspector instance. */ public static Uberspect getUberspect(Log logger) { if (logger == null || logger.equals(LogFactory.getLog(JexlEngine.class))) { return UberspectHolder.UBERSPECT; } return new UberspectImpl(logger); } /** * Gets this engine underlying uberspect. * @return the uberspect */ public Uberspect getUberspect() { return uberspect; } /** * Gets this engine underlying arithmetic. * @return the arithmetic * @since 2.1 */ public JexlArithmetic getArithmetic() { return arithmetic; } /** * Sets whether this engine reports debugging information when error occurs. *

This method is not thread safe; it should be called as an optional step of the JexlEngine * initialization code before expression creation & evaluation.

* @see JexlEngine#setSilent * @see JexlEngine#setLenient * @param flag true implies debug is on, false implies debug is off. */ public void setDebug(boolean flag) { this.debug = flag; } /** * Checks whether this engine is in debug mode. * @return true if debug is on, false otherwise */ public boolean isDebug() { return this.debug; } /** * Sets whether this engine throws JexlException during evaluation when an error is triggered. *

This method is not thread safe; it should be called as an optional step of the JexlEngine * initialization code before expression creation & evaluation.

* @see JexlEngine#setDebug * @see JexlEngine#setLenient * @param flag true means no JexlException will occur, false allows them */ public void setSilent(boolean flag) { this.silent = flag; } /** * Checks whether this engine throws JexlException during evaluation. * @return true if silent, false (default) otherwise */ public boolean isSilent() { return this.silent; } /** * Sets whether this engine considers unknown variables, methods and constructors as errors or evaluates them * as null or zero. *

This method is not thread safe; it should be called as an optional step of the JexlEngine * initialization code before expression creation & evaluation.

*

As of 2.1, you can use a JexlThreadedArithmetic instance to allow the JexlArithmetic * leniency behavior to be independently specified per thread, whilst still using a single engine.

* @see JexlEngine#setSilent * @see JexlEngine#setDebug * @param flag true means no JexlException will occur, false allows them */ @SuppressWarnings("deprecation") public void setLenient(boolean flag) { if (arithmetic instanceof JexlThreadedArithmetic) { JexlThreadedArithmetic.setLenient(Boolean.valueOf(flag)); } else { this.arithmetic.setLenient(flag); } } /** * Checks whether this engine considers unknown variables, methods and constructors as errors. * @return true if lenient, false if strict */ public boolean isLenient() { return arithmetic.isLenient(); } /** * Sets whether this engine behaves in strict or lenient mode. * Equivalent to setLenient(!flag). *

This method is not thread safe; it should be called as an optional step of the JexlEngine * initialization code before expression creation & evaluation.

* @param flag true for strict, false for lenient * @since 2.1 */ public final void setStrict(boolean flag) { setLenient(!flag); } /** * Checks whether this engine behaves in strict or lenient mode. * Equivalent to !isLenient(). * @return true for strict, false for lenient * @since 2.1 */ public final boolean isStrict() { return !isLenient(); } /** * Sets the class loader used to discover classes in 'new' expressions. *

This method should be called as an optional step of the JexlEngine * initialization code before expression creation & evaluation.

* @param loader the class loader to use */ public void setClassLoader(ClassLoader loader) { uberspect.setClassLoader(loader); } /** * Sets a cache for expressions of the defined size. *

The cache will contain at most size expressions. Note that * all JEXL caches are held through SoftReferences and may be garbage-collected.

* @param size if not strictly positive, no cache is used. */ public void setCache(int size) { // since the cache is only used during parse, use same sync object synchronized (parser) { if (size <= 0) { cache = null; } else if (cache == null || cache.size() != size) { cache = new SoftCache(size); } } } /** * Sets the map of function namespaces. *

* This method is not thread safe; it should be called as an optional step of the JexlEngine * initialization code before expression creation & evaluation. *

*

* Each entry key is used as a prefix, each entry value used as a bean implementing * methods; an expression like 'nsx:method(123)' will thus be solved by looking at * a registered bean named 'nsx' that implements method 'method' in that map. * If all methods are static, you may use the bean class instead of an instance as value. *

*

* If the entry value is a class that has one contructor taking a JexlContext as argument, an instance * of the namespace will be created at evaluation time. It might be a good idea to derive a JexlContext * to carry the information used by the namespace to avoid variable space pollution and strongly type * the constructor with this specialized JexlContext. *

*

* The key or prefix allows to retrieve the bean that plays the role of the namespace. * If the prefix is null, the namespace is the top-level namespace allowing to define * top-level user defined functions ( ie: myfunc(...) ) *

*

Note that the JexlContext is also used to try to solve top-level functions. This allows ObjectContext * derived instances to call methods on the wrapped object.

* @param funcs the map of functions that should not mutate after the call; if null * is passed, the empty collection is used. */ public void setFunctions(Map funcs) { functions = funcs != null ? funcs : Collections.emptyMap(); } /** * Retrieves the map of function namespaces. * * @return the map passed in setFunctions or the empty map if the * original was null. */ public Map getFunctions() { return functions; } /** * An overridable through covariant return Expression creator. * @param text the script text * @param tree the parse AST tree * @return the script instance */ protected Expression createExpression(ASTJexlScript tree, String text) { return new ExpressionImpl(this, text, tree); } /** * Creates an Expression from a String containing valid * JEXL syntax. This method parses the expression which * must contain either a reference or an expression. * @param expression A String containing valid JEXL syntax * @return An Expression object which can be evaluated with a JexlContext * @throws JexlException An exception can be thrown if there is a problem * parsing this expression, or if the expression is neither an * expression nor a reference. */ public Expression createExpression(String expression) { return createExpression(expression, null); } /** * Creates an Expression from a String containing valid * JEXL syntax. This method parses the expression which * must contain either a reference or an expression. * @param expression A String containing valid JEXL syntax * @return An Expression object which can be evaluated with a JexlContext * @param info An info structure to carry debugging information if needed * @throws JexlException An exception can be thrown if there is a problem * parsing this expression, or if the expression is neither an * expression or a reference. */ public Expression createExpression(String expression, JexlInfo info) { // Parse the expression ASTJexlScript tree = parse(expression, info, null); if (tree.jjtGetNumChildren() > 1) { logger.warn("The JEXL Expression created will be a reference" + " to the first expression from the supplied script: \"" + expression + "\" "); } return createExpression(tree, expression); } /** * Creates a Script from a String containing valid JEXL syntax. * This method parses the script which validates the syntax. * * @param scriptText A String containing valid JEXL syntax * @return A {@link Script} which can be executed using a {@link JexlContext}. * @throws JexlException if there is a problem parsing the script. */ public Script createScript(String scriptText) { return createScript(scriptText, null, null); } /** * Creates a Script from a String containing valid JEXL syntax. * This method parses the script which validates the syntax. * * @param scriptText A String containing valid JEXL syntax * @param info An info structure to carry debugging information if needed * @return A {@link Script} which can be executed using a {@link JexlContext}. * @throws JexlException if there is a problem parsing the script. * @deprecated Use {@link #createScript(String, JexlInfo, String[])} */ @Deprecated public Script createScript(String scriptText, JexlInfo info) { if (scriptText == null) { throw new NullPointerException("scriptText is null"); } // Parse the expression ASTJexlScript tree = parse(scriptText, info); return createScript(tree, scriptText); } /** * Creates a Script from a String containing valid JEXL syntax. * This method parses the script which validates the syntax. * * @param scriptText A String containing valid JEXL syntax * @param names the script parameter names * @return A {@link Script} which can be executed using a {@link JexlContext}. * @throws JexlException if there is a problem parsing the script. */ public Script createScript(String scriptText, String... names) { return createScript(scriptText, null, names); } /** * Creates a Script from a String containing valid JEXL syntax. * This method parses the script which validates the syntax. * It uses an array of parameter names that will be resolved during parsing; * a corresponding array of arguments containing values should be used during evaluation. * * @param scriptText A String containing valid JEXL syntax * @param info An info structure to carry debugging information if needed * @param names the script parameter names * @return A {@link Script} which can be executed using a {@link JexlContext}. * @throws JexlException if there is a problem parsing the script. * @since 2.1 */ public Script createScript(String scriptText, JexlInfo info, String[] names) { if (scriptText == null) { throw new NullPointerException("scriptText is null"); } // Parse the expression ASTJexlScript tree = parse(scriptText, info, new Scope(names)); return createScript(tree, scriptText); } /** * An overridable through covariant return Script creator. * @param text the script text * @param tree the parse AST tree * @return the script instance */ protected Script createScript(ASTJexlScript tree, String text) { return new ExpressionImpl(this, text, tree); } /** * Creates a Script from a {@link File} containing valid JEXL syntax. * This method parses the script and validates the syntax. * * @param scriptFile A {@link File} containing valid JEXL syntax. * Must not be null. Must be a readable file. * @return A {@link Script} which can be executed with a * {@link JexlContext}. * @throws IOException if there is a problem reading the script. * @throws JexlException if there is a problem parsing the script. */ public Script createScript(File scriptFile) throws IOException { if (scriptFile == null) { throw new NullPointerException("scriptFile is null"); } if (!scriptFile.canRead()) { throw new IOException("Can't read scriptFile (" + scriptFile.getCanonicalPath() + ")"); } BufferedReader reader = new BufferedReader(new FileReader(scriptFile)); JexlInfo info = null; if (debug) { info = createInfo(scriptFile.getName(), 0, 0); } return createScript(readerToString(reader), info, null); } /** * Creates a Script from a {@link URL} containing valid JEXL syntax. * This method parses the script and validates the syntax. * * @param scriptUrl A {@link URL} containing valid JEXL syntax. * Must not be null. Must be a readable file. * @return A {@link Script} which can be executed with a * {@link JexlContext}. * @throws IOException if there is a problem reading the script. * @throws JexlException if there is a problem parsing the script. */ public Script createScript(URL scriptUrl) throws IOException { if (scriptUrl == null) { throw new NullPointerException("scriptUrl is null"); } URLConnection connection = scriptUrl.openConnection(); BufferedReader reader = new BufferedReader( new InputStreamReader(connection.getInputStream())); JexlInfo info = null; if (debug) { info = createInfo(scriptUrl.toString(), 0, 0); } return createScript(readerToString(reader), info, null); } /** * Accesses properties of a bean using an expression. *

* jexl.get(myobject, "foo.bar"); should equate to * myobject.getFoo().getBar(); (or myobject.getFoo().get("bar")) *

*

* If the JEXL engine is silent, errors will be logged through its logger as warning. *

* @param bean the bean to get properties from * @param expr the property expression * @return the value of the property * @throws JexlException if there is an error parsing the expression or during evaluation */ public Object getProperty(Object bean, String expr) { return getProperty(null, bean, expr); } /** * Accesses properties of a bean using an expression. *

* If the JEXL engine is silent, errors will be logged through its logger as warning. *

* @param context the evaluation context * @param bean the bean to get properties from * @param expr the property expression * @return the value of the property * @throws JexlException if there is an error parsing the expression or during evaluation */ public Object getProperty(JexlContext context, Object bean, String expr) { if (context == null) { context = EMPTY_CONTEXT; } // synthetize expr using register expr = "#0" + (expr.charAt(0) == '[' ? "" : ".") + expr + ";"; try { parser.ALLOW_REGISTERS = true; Scope frame = new Scope("#0"); ASTJexlScript script = parse(expr, null, frame); JexlNode node = script.jjtGetChild(0); Interpreter interpreter = createInterpreter(context); // set frame interpreter.setFrame(script.createFrame(bean)); return node.jjtAccept(interpreter, null); } catch (JexlException xjexl) { if (silent) { logger.warn(xjexl.getMessage(), xjexl.getCause()); return null; } throw xjexl; } finally { parser.ALLOW_REGISTERS = false; } } /** * Assign properties of a bean using an expression. *

* jexl.set(myobject, "foo.bar", 10); should equate to * myobject.getFoo().setBar(10); (or myobject.getFoo().put("bar", 10) ) *

*

* If the JEXL engine is silent, errors will be logged through its logger as warning. *

* @param bean the bean to set properties in * @param expr the property expression * @param value the value of the property * @throws JexlException if there is an error parsing the expression or during evaluation */ public void setProperty(Object bean, String expr, Object value) { setProperty(null, bean, expr, value); } /** * Assign properties of a bean using an expression. *

* If the JEXL engine is silent, errors will be logged through its logger as warning. *

* @param context the evaluation context * @param bean the bean to set properties in * @param expr the property expression * @param value the value of the property * @throws JexlException if there is an error parsing the expression or during evaluation */ public void setProperty(JexlContext context, Object bean, String expr, Object value) { if (context == null) { context = EMPTY_CONTEXT; } // synthetize expr using registers expr = "#0" + (expr.charAt(0) == '[' ? "" : ".") + expr + "=" + "#1" + ";"; try { parser.ALLOW_REGISTERS = true; Scope frame = new Scope("#0", "#1"); ASTJexlScript script = parse(expr, null, frame); JexlNode node = script.jjtGetChild(0); Interpreter interpreter = createInterpreter(context); // set the registers interpreter.setFrame(script.createFrame(bean, value)); node.jjtAccept(interpreter, null); } catch (JexlException xjexl) { if (silent) { logger.warn(xjexl.getMessage(), xjexl.getCause()); return; } throw xjexl; } finally { parser.ALLOW_REGISTERS = false; } } /** * Invokes an object's method by name and arguments. * @param obj the method's invoker object * @param meth the method's name * @param args the method's arguments * @return the method returned value or null if it failed and engine is silent * @throws JexlException if method could not be found or failed and engine is not silent */ public Object invokeMethod(Object obj, String meth, Object... args) { JexlException xjexl = null; Object result = null; JexlInfo info = debugInfo(); try { JexlMethod method = uberspect.getMethod(obj, meth, args, info); if (method == null && arithmetic.narrowArguments(args)) { method = uberspect.getMethod(obj, meth, args, info); } if (method != null) { result = method.invoke(obj, args); } else { xjexl = new JexlException(info, "failed finding method " + meth); } } catch (Exception xany) { xjexl = new JexlException(info, "failed executing method " + meth, xany); } finally { if (xjexl != null) { if (silent) { logger.warn(xjexl.getMessage(), xjexl.getCause()); return null; } throw xjexl; } } return result; } /** * Creates a new instance of an object using the most appropriate constructor * based on the arguments. * @param the type of object * @param clazz the class to instantiate * @param args the constructor arguments * @return the created object instance or null on failure when silent */ public T newInstance(Class clazz, Object... args) { return clazz.cast(doCreateInstance(clazz, args)); } /** * Creates a new instance of an object using the most appropriate constructor * based on the arguments. * @param clazz the name of the class to instantiate resolved through this engine's class loader * @param args the constructor arguments * @return the created object instance or null on failure when silent */ public Object newInstance(String clazz, Object... args) { return doCreateInstance(clazz, args); } /** * Creates a new instance of an object using the most appropriate constructor * based on the arguments. * @param clazz the class to instantiate * @param args the constructor arguments * @return the created object instance or null on failure when silent */ protected Object doCreateInstance(Object clazz, Object... args) { JexlException xjexl = null; Object result = null; JexlInfo info = debugInfo(); try { JexlMethod ctor = uberspect.getConstructorMethod(clazz, args, info); if (ctor == null && arithmetic.narrowArguments(args)) { ctor = uberspect.getConstructorMethod(clazz, args, info); } if (ctor != null) { result = ctor.invoke(clazz, args); } else { xjexl = new JexlException(info, "failed finding constructor for " + clazz.toString()); } } catch (Exception xany) { xjexl = new JexlException(info, "failed executing constructor for " + clazz.toString(), xany); } finally { if (xjexl != null) { if (silent) { logger.warn(xjexl.getMessage(), xjexl.getCause()); return null; } throw xjexl; } } return result; } /** * Creates an interpreter. * @param context a JexlContext; if null, the EMPTY_CONTEXT is used instead. * @return an Interpreter */ protected Interpreter createInterpreter(JexlContext context) { return createInterpreter(context, isStrict(), isSilent()); } /** * Creates an interpreter. * @param context a JexlContext; if null, the EMPTY_CONTEXT is used instead. * @param strictFlag whether the interpreter runs in strict mode * @param silentFlag whether the interpreter runs in silent mode * @return an Interpreter * @since 2.1 */ protected Interpreter createInterpreter(JexlContext context, boolean strictFlag, boolean silentFlag) { return new Interpreter(this, context == null ? EMPTY_CONTEXT : context, strictFlag, silentFlag); } /** * A soft reference on cache. *

The cache is held through a soft reference, allowing it to be GCed under * memory pressure.

* @param the cache key entry type * @param the cache key value type */ protected class SoftCache { /** * The cache size. */ private final int size; /** * The soft reference to the cache map. */ private SoftReference> ref = null; /** * Creates a new instance of a soft cache. * @param theSize the cache size */ SoftCache(int theSize) { size = theSize; } /** * Returns the cache size. * @return the cache size */ int size() { return size; } /** * Clears the cache. */ void clear() { ref = null; } /** * Produces the cache entry set. * @return the cache entry set */ Set> entrySet() { Map map = ref != null ? ref.get() : null; return map != null ? map.entrySet() : Collections.>emptySet(); } /** * Gets a value from cache. * @param key the cache entry key * @return the cache entry value */ V get(K key) { final Map map = ref != null ? ref.get() : null; return map != null ? map.get(key) : null; } /** * Puts a value in cache. * @param key the cache entry key * @param script the cache entry value */ void put(K key, V script) { Map map = ref != null ? ref.get() : null; if (map == null) { map = createCache(size); ref = new SoftReference>(map); } map.put(key, script); } } /** * Creates a cache. * @param the key type * @param the value type * @param cacheSize the cache size, must be > 0 * @return a Map usable as a cache bounded to the given size */ protected Map createCache(final int cacheSize) { return new java.util.LinkedHashMap(cacheSize, LOAD_FACTOR, true) { /** Serial version UID. */ private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > cacheSize; } }; } /** * Clears the expression cache. * @since 2.1 */ public void clearCache() { synchronized (parser) { cache.clear(); } } /** * Gets the list of variables accessed by a script. *

This method will visit all nodes of a script and extract all variables whether they * are written in 'dot' or 'bracketed' notation. (a.b is equivalent to a['b']).

* @param script the script * @return the set of variables, each as a list of strings (ant-ish variables use more than 1 string) * or the empty set if no variables are used * @since 2.1 */ public Set> getVariables(Script script) { if (script instanceof ExpressionImpl) { Set> refs = new LinkedHashSet>(); getVariables(((ExpressionImpl) script).script, refs, null); return refs; } else { return Collections.>emptySet(); } } /** * Fills up the list of variables accessed by a node. * @param node the node * @param refs the set of variable being filled * @param ref the current variable being filled * @since 2.1 */ protected void getVariables(JexlNode node, Set> refs, List ref) { boolean array = node instanceof ASTArrayAccess; boolean reference = node instanceof ASTReference; int num = node.jjtGetNumChildren(); if (array || reference) { List var = ref != null ? ref : new ArrayList(); boolean varf = true; for (int i = 0; i < num; ++i) { JexlNode child = node.jjtGetChild(i); if (array) { if (child instanceof ASTReference && child.jjtGetNumChildren() == 1) { JexlNode desc = child.jjtGetChild(0); if (varf && desc.isConstant()) { String image = desc.image; if (image == null) { var.add(new Debugger().data(desc)); } else { var.add(image); } } else if (desc instanceof ASTIdentifier) { if (((ASTIdentifier) desc).getRegister() < 0) { List di = new ArrayList(1); di.add(desc.image); refs.add(di); } var = new ArrayList(); varf = false; } continue; } else if (child instanceof ASTIdentifier) { if (i == 0 && (((ASTIdentifier) child).getRegister() < 0)) { var.add(child.image); } continue; } } else {//if (reference) { if (child instanceof ASTIdentifier) { if (((ASTIdentifier) child).getRegister() < 0) { var.add(child.image); } continue; } } getVariables(child, refs, var); } if (!var.isEmpty() && var != ref) { refs.add(var); } } else { for (int i = 0; i < num; ++i) { getVariables(node.jjtGetChild(i), refs, null); } } } /** * Gets the array of parameters from a script. * @param script the script * @return the parameters which may be empty (but not null) if no parameters were defined * @since 2.1 */ protected String[] getParameters(Script script) { if (script instanceof ExpressionImpl) { return ((ExpressionImpl) script).getParameters(); } else { return new String[0]; } } /** * Gets the array of local variable from a script. * @param script the script * @return the local variables array which may be empty (but not null) if no local variables were defined * @since 2.1 */ protected String[] getLocalVariables(Script script) { if (script instanceof ExpressionImpl) { return ((ExpressionImpl) script).getLocalVariables(); } else { return new String[0]; } } /** * A script scope, stores the declaration of parameters and local variables. * @since 2.1 */ public static final class Scope { /** * The number of parameters. */ private final int parms; /** * The map of named registers aka script parameters. * Each parameter is associated to a register and is materialized as an offset in the registers array used * during evaluation. */ private Map namedRegisters = null; /** * Creates a new scope with a list of parameters. * @param parameters the list of parameters */ public Scope(String... parameters) { if (parameters != null) { parms = parameters.length; namedRegisters = new LinkedHashMap(); for (int p = 0; p < parms; ++p) { namedRegisters.put(parameters[p], Integer.valueOf(p)); } } else { parms = 0; } } @Override public int hashCode() { return namedRegisters == null ? 0 : parms ^ namedRegisters.hashCode(); } @Override public boolean equals(Object o) { return o instanceof Scope && equals((Scope) o); } /** * Whether this frame is equal to another. * @param frame the frame to compare to * @return true if equal, false otherwise */ public boolean equals(Scope frame) { if (this == frame) { return true; } else if (frame == null || parms != frame.parms) { return false; } else if (namedRegisters == null) { return frame.namedRegisters == null; } else { return namedRegisters.equals(frame.namedRegisters); } } /** * Checks whether an identifier is a local variable or argument, ie stored in a register. * @param name the register name * @return the register index */ public Integer getRegister(String name) { return namedRegisters != null ? namedRegisters.get(name) : null; } /** * Declares a local variable. *

* This method creates an new entry in the named register map. *

* @param name the variable name * @return the register index storing this variable */ public Integer declareVariable(String name) { if (namedRegisters == null) { namedRegisters = new LinkedHashMap(); } Integer register = namedRegisters.get(name); if (register == null) { register = Integer.valueOf(namedRegisters.size()); namedRegisters.put(name, register); } return register; } /** * Creates a frame by copying values up to the number of parameters. * @param values the argument values * @return the arguments array */ public Frame createFrame(Object... values) { if (namedRegisters != null) { Object[] arguments = new Object[namedRegisters.size()]; if (values != null) { System.arraycopy(values, 0, arguments, 0, Math.min(parms, values.length)); } return new Frame(arguments, namedRegisters.keySet().toArray(new String[0])); } else { return null; } } /** * Gets the (maximum) number of arguments this script expects. * @return the number of parameters */ public int getArgCount() { return parms; } /** * Gets this script registers, i.e. parameters and local variables. * @return the register names */ public String[] getRegisters() { return namedRegisters != null ? namedRegisters.keySet().toArray(new String[0]) : new String[0]; } /** * Gets this script parameters, i.e. registers assigned before creating local variables. * @return the parameter names */ public String[] getParameters() { if (namedRegisters != null && parms > 0) { String[] pa = new String[parms]; int p = 0; for (Map.Entry entry : namedRegisters.entrySet()) { if (entry.getValue().intValue() < parms) { pa[p++] = entry.getKey(); } } return pa; } else { return null; } } /** * Gets this script local variable, i.e. registers assigned to local variables. * @return the parameter names */ public String[] getLocalVariables() { if (namedRegisters != null && parms > 0) { String[] pa = new String[parms]; int p = 0; for (Map.Entry entry : namedRegisters.entrySet()) { if (entry.getValue().intValue() >= parms) { pa[p++] = entry.getKey(); } } return pa; } else { return null; } } } /** * A call frame, created from a scope, stores the arguments and local variables as "registers". * @since 2.1 */ public static final class Frame { /** Registers or arguments. */ private Object[] registers = null; /** Parameter and argument names if any. */ private String[] parameters = null; /** * Creates a new frame. * @param r the registers * @param p the parameters */ Frame(Object[] r, String[] p) { registers = r; parameters = p; } /** * @return the registers */ public Object[] getRegisters() { return registers; } /** * @return the parameters */ public String[] getParameters() { return parameters; } } /** * Parses an expression. * @param expression the expression to parse * @param info debug information structure * @return the parsed tree * @throws JexlException if any error occured during parsing * @deprecated Use {@link #parse(CharSequence, JexlInfo, Scope)} instead */ @Deprecated protected ASTJexlScript parse(CharSequence expression, JexlInfo info) { return parse(expression, info, null); } /** * Parses an expression. * @param expression the expression to parse * @param info debug information structure * @param frame the script frame to use * @return the parsed tree * @throws JexlException if any error occured during parsing */ protected ASTJexlScript parse(CharSequence expression, JexlInfo info, Scope frame) { String expr = cleanExpression(expression); ASTJexlScript script = null; JexlInfo dbgInfo = null; synchronized (parser) { if (cache != null) { script = cache.get(expr); if (script != null) { Scope f = script.getScope(); if ((f == null && frame == null) || (f != null && f.equals(frame))) { return script; } } } try { Reader reader = new StringReader(expr); // use first calling method of JexlEngine as debug info if (info == null) { dbgInfo = debugInfo(); } else { dbgInfo = info.debugInfo(); } parser.setFrame(frame); script = parser.parse(reader, dbgInfo); // reaccess in case local variables have been declared frame = parser.getFrame(); if (frame != null) { script.setScope(frame); } if (cache != null) { cache.put(expr, script); } } catch (TokenMgrError xtme) { throw new JexlException.Tokenization(dbgInfo, expression, xtme); } catch (ParseException xparse) { throw new JexlException.Parsing(dbgInfo, expression, xparse); } finally { parser.setFrame(null); } } return script; } /** * Creates a JexlInfo instance. * @param fn url/file name * @param l line number * @param c column number * @return a JexlInfo instance */ protected JexlInfo createInfo(String fn, int l, int c) { return new DebugInfo(fn, l, c); } /** * Creates and fills up debugging information. *

This gathers the class, method and line number of the first calling method * not owned by JexlEngine, UnifiedJEXL or {Script,Expression}Factory.

* @return an Info if debug is set, null otherwise */ protected JexlInfo debugInfo() { DebugInfo info = null; if (debug) { Throwable xinfo = new Throwable(); xinfo.fillInStackTrace(); StackTraceElement[] stack = xinfo.getStackTrace(); StackTraceElement se = null; Class clazz = getClass(); for (int s = 1; s < stack.length; ++s, se = null) { se = stack[s]; String className = se.getClassName(); if (!className.equals(clazz.getName())) { // go deeper if called from JexlEngine or UnifiedJEXL if (className.equals(JexlEngine.class.getName())) { clazz = JexlEngine.class; } else if (className.equals(UnifiedJEXL.class.getName())) { clazz = UnifiedJEXL.class; } else { break; } } } if (se != null) { info = createInfo(se.getClassName() + "." + se.getMethodName(), se.getLineNumber(), 0).debugInfo(); } } return info; } /** * Trims the expression from front & ending spaces. * @param str expression to clean * @return trimmed expression ending in a semi-colon */ public static String cleanExpression(CharSequence str) { if (str != null) { int start = 0; int end = str.length(); if (end > 0) { // trim front spaces while (start < end && str.charAt(start) == ' ') { ++start; } // trim ending spaces while (end > 0 && str.charAt(end - 1) == ' ') { --end; } return str.subSequence(start, end).toString(); } return ""; } return null; } /** * Read from a reader into a local buffer and return a String with * the contents of the reader. * @param scriptReader to be read. * @return the contents of the reader as a String. * @throws IOException on any error reading the reader. */ public static String readerToString(Reader scriptReader) throws IOException { StringBuilder buffer = new StringBuilder(); BufferedReader reader; if (scriptReader instanceof BufferedReader) { reader = (BufferedReader) scriptReader; } else { reader = new BufferedReader(scriptReader); } try { String line; while ((line = reader.readLine()) != null) { buffer.append(line).append('\n'); } return buffer.toString(); } finally { try { reader.close(); } catch (IOException xio) { // ignore } } } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/JexlException.java100644 0 0 31541 11673634324 24666 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.UndeclaredThrowableException; import org.apache.commons.jexl2.parser.JexlNode; import org.apache.commons.jexl2.parser.ParseException; import org.apache.commons.jexl2.parser.TokenMgrError; /** * Wraps any error that might occur during interpretation of a script or expression. * @since 2.0 */ public class JexlException extends RuntimeException { /** The point of origin for this exception. */ protected final transient JexlNode mark; /** The debug info. */ protected final transient JexlInfo info; /** A marker to use in NPEs stating a null operand error. */ public static final String NULL_OPERAND = "jexl.null"; /** Minimum number of characters around exception location. */ private static final int MIN_EXCHARLOC = 5; /** Maximum number of characters around exception location. */ private static final int MAX_EXCHARLOC = 10; /** * Creates a new JexlException. * @param node the node causing the error * @param msg the error message */ public JexlException(JexlNode node, String msg) { super(msg); mark = node; info = node != null ? node.debugInfo() : null; } /** * Creates a new JexlException. * @param node the node causing the error * @param msg the error message * @param cause the exception causing the error */ public JexlException(JexlNode node, String msg, Throwable cause) { super(msg, unwrap(cause)); mark = node; info = node != null ? node.debugInfo() : null; } /** * Creates a new JexlException. * @param dbg the debugging information associated * @param msg the error message */ public JexlException(JexlInfo dbg, String msg) { super(msg); mark = null; info = dbg; } /** * Creates a new JexlException. * @param dbg the debugging information associated * @param msg the error message * @param cause the exception causing the error */ public JexlException(JexlInfo dbg, String msg, Throwable cause) { super(msg, unwrap(cause)); mark = null; info = dbg; } /** * Unwraps the cause of a throwable due to reflection. * @param xthrow the throwable * @return the cause */ private static Throwable unwrap(Throwable xthrow) { if (xthrow instanceof InvocationTargetException) { return ((InvocationTargetException) xthrow).getTargetException(); } else if (xthrow instanceof UndeclaredThrowableException) { return ((UndeclaredThrowableException) xthrow).getUndeclaredThrowable(); } else { return xthrow; } } /** * Accesses detailed message. * @return the message * @since 2.1 */ protected String detailedMessage() { return super.getMessage(); } /** * Formats an error message from the parser. * @param prefix the prefix to the message * @param expr the expression in error * @return the formatted message * @since 2.1 */ protected String parserError(String prefix, String expr) { int begin = info.debugInfo().getColumn(); int end = begin + MIN_EXCHARLOC; begin -= MIN_EXCHARLOC; if (begin < 0) { end += MIN_EXCHARLOC; begin = 0; } int length = expr.length(); if (length < MAX_EXCHARLOC) { return prefix + " error in '" + expr + "'"; } else { return prefix + " error near '... " + expr.substring(begin, end > length ? length : end) + " ...'"; } } /** * Thrown when tokenization fails. * @since 2.1 */ public static class Tokenization extends JexlException { /** * Creates a new Tokenization exception instance. * @param node the location info * @param expr the expression * @param cause the javacc cause */ public Tokenization(JexlInfo node, CharSequence expr, TokenMgrError cause) { super(merge(node, cause), expr.toString(), cause); } /** * Merge the node info and the cause info to obtain best possible location. * @param node the node * @param cause the cause * @return the info to use */ private static DebugInfo merge(JexlInfo node, TokenMgrError cause) { DebugInfo dbgn = node != null ? node.debugInfo() : null; if (cause == null) { return dbgn; } else if (dbgn == null) { return new DebugInfo("", cause.getLine(), cause.getColumn()); } else { return new DebugInfo(dbgn.getName(), cause.getLine(), cause.getColumn()); } } /** * @return the expression */ public String getExpression() { return super.detailedMessage(); } @Override protected String detailedMessage() { return parserError("tokenization", getExpression()); } } /** * Thrown when parsing fails. * @since 2.1 */ public static class Parsing extends JexlException { /** * Creates a new Variable exception instance. * @param node the offending ASTnode * @param expr the offending source * @param cause the javacc cause */ public Parsing(JexlInfo node, CharSequence expr, ParseException cause) { super(merge(node, cause), expr.toString(), cause); } /** * Merge the node info and the cause info to obtain best possible location. * @param node the node * @param cause the cause * @return the info to use */ private static DebugInfo merge(JexlInfo node, ParseException cause) { DebugInfo dbgn = node != null ? node.debugInfo() : null; if (cause == null) { return dbgn; } else if (dbgn == null) { return new DebugInfo("", cause.getLine(), cause.getColumn()); } else { return new DebugInfo(dbgn.getName(), cause.getLine(), cause.getColumn()); } } /** * @return the expression */ public String getExpression() { return super.detailedMessage(); } @Override protected String detailedMessage() { return parserError("parsing", getExpression()); } } /** * Thrown when a variable is unknown. * @since 2.1 */ public static class Variable extends JexlException { /** * Creates a new Variable exception instance. * @param node the offending ASTnode * @param var the unknown variable */ public Variable(JexlNode node, String var) { super(node, var); } /** * @return the variable name */ public String getVariable() { return super.detailedMessage(); } @Override protected String detailedMessage() { return "undefined variable " + getVariable(); } } /** * Thrown when a property is unknown. * @since 2.1 */ public static class Property extends JexlException { /** * Creates a new Property exception instance. * @param node the offending ASTnode * @param var the unknown variable */ public Property(JexlNode node, String var) { super(node, var); } /** * @return the property name */ public String getProperty() { return super.detailedMessage(); } @Override protected String detailedMessage() { return "inaccessible or unknown property " + getProperty(); } } /** * Thrown when a method or ctor is unknown, ambiguous or inaccessible. * @since 2.1 */ public static class Method extends JexlException { /** * Creates a new Method exception instance. * @param node the offending ASTnode * @param name the unknown method */ public Method(JexlNode node, String name) { super(node, name); } /** * @return the method name */ public String getMethod() { return super.detailedMessage(); } @Override protected String detailedMessage() { return "unknown, ambiguous or inaccessible method " + getMethod(); } } /** * Thrown to return a value. * @since 2.1 */ protected static class Return extends JexlException { /** The returned value. */ private final Object result; /** * Creates a new instance of Return. * @param node the return node * @param msg the message * @param value the returned value */ protected Return(JexlNode node, String msg, Object value) { super(node, msg); this.result = value; } /** * @return the returned value */ public Object getValue() { return result; } } /** * Thrown to cancel a script execution. * @since 2.1 */ protected static class Cancel extends JexlException { /** * Creates a new instance of Cancel. * @param node the node where the interruption was detected */ protected Cancel(JexlNode node) { super(node, "execution cancelled", null); } } /** * Gets information about the cause of this error. *

* The returned string represents the outermost expression in error. * The info parameter, an int[2] optionally provided by the caller, will be filled with the begin/end offset * characters of the precise error's trigger. *

* @param offsets character offset interval of the precise node triggering the error * @return a string representation of the offending expression, the empty string if it could not be determined */ public String getInfo(int[] offsets) { Debugger dbg = new Debugger(); if (dbg.debug(mark)) { if (offsets != null && offsets.length >= 2) { offsets[0] = dbg.start(); offsets[1] = dbg.end(); } return dbg.data(); } return ""; } /** * Detailed info message about this error. * Format is "debug![begin,end]: string \n msg" where: * - debug is the debugging information if it exists (@link JexlEngine.setDebug) * - begin, end are character offsets in the string for the precise location of the error * - string is the string representation of the offending expression * - msg is the actual explanation message for this error * @return this error as a string */ @Override public String getMessage() { Debugger dbg = new Debugger(); StringBuilder msg = new StringBuilder(); if (info != null) { msg.append(info.debugString()); } if (dbg.debug(mark)) { msg.append("!["); msg.append(dbg.start()); msg.append(","); msg.append(dbg.end()); msg.append("]: '"); msg.append(dbg.data()); msg.append("'"); } msg.append(' '); msg.append(detailedMessage()); Throwable cause = getCause(); if (cause != null && NULL_OPERAND == cause.getMessage()) { msg.append(" caused by null operand"); } return msg.toString(); } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/JexlInfo.java100644 0 0 2376 11673634323 23606 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Interface for objects carrying information usefull to debugging. * @since 1.0 */ public interface JexlInfo { /** * Formats this information for debugging purpose. * @return a human readable string. */ String debugString(); /** * Gets the underlying debugging information. * @return a debug info instance * @since 2.1 */ DebugInfo debugInfo(); } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/JexlThreadedArithmetic.java100644 0 0 10503 11673634323 26454 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.math.MathContext; /** * A derived arithmetic that allows different threads to operate with * different strict/lenient/math modes using the same JexlEngine. * @since 2.1 */ public class JexlThreadedArithmetic extends JexlArithmetic { /** Holds the threaded version of some arithmetic features. */ static class Features { /** Default ctor. */ Features() {} /** Whether this JexlArithmetic instance behaves in strict or lenient mode. */ private Boolean lenient = null; /** The big decimal math context. */ private MathContext mathContext = null; /** The big decimal scale. */ private Integer mathScale = null; } /** * Standard ctor. * @param lenient lenient versus strict evaluation flag */ public JexlThreadedArithmetic(boolean lenient) { super(lenient); } /** * Creates a JexlThreadedArithmetic instance. * @param lenient whether this arithmetic is lenient or strict * @param bigdContext the math context instance to use for +,-,/,*,% operations on big decimals. * @param bigdScale the scale used for big decimals. */ public JexlThreadedArithmetic(boolean lenient, MathContext bigdContext, int bigdScale) { super(lenient, bigdContext, bigdScale); } /** Whether this JexlArithmetic instance behaves in strict or lenient mode for this thread. */ static final ThreadLocal FEATURES = new ThreadLocal() { @Override protected synchronized Features initialValue() { return new Features(); } }; /** * Overrides the default behavior and sets whether this JexlArithmetic instance triggers errors * during evaluation when null is used as an operand for the current thread. *

It is advised to protect calls by either calling JexlThreadedArithmetic.setLenient explicitly * before evaluation or add a try/finally clause resetting the flag to avoid unexpected reuse of the lenient * flag value through thread pools side-effects.

* @see JexlEngine#setSilent * @see JexlEngine#setDebug * @param flag true means no JexlException will occur, false allows them, null reverts to default behavior */ public static void setLenient(Boolean flag) { FEATURES.get().lenient = flag; } /** * Sets the math scale. *

The goal and constraints are the same than for setLenient.

* @param scale the scale */ public static void setMathScale(Integer scale) { FEATURES.get().mathScale = scale; } /** * Sets the math context. *

The goal and constraints are the same than for setLenient.

* @param mc the math context */ public static void setMathContext(MathContext mc) { FEATURES.get().mathContext = mc; } /** {@inheritDoc} */ @Override public boolean isLenient() { Boolean lenient = FEATURES.get().lenient; return lenient == null ? super.isLenient() : lenient.booleanValue(); } @Override public int getMathScale() { Integer scale = FEATURES.get().mathScale; return scale == null ? super.getMathScale() : scale.intValue(); } @Override public MathContext getMathContext() { MathContext mc = FEATURES.get().mathContext; return mc == null? super.getMathContext() : mc; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/Main.java100644 0 0 5235 11673634324 22752 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; /** * Test application for JEXL. * * @since 2.0 */ public class Main { /** * Test application for JEXL * * If a single argument is present, it is treated as a filename of a JEXL * script to be executed as a script. Any exceptions terminate the application. * * Otherwise, lines are read from standard input and evaluated. * ParseExceptions and JexlExceptions are logged, and do not cause the application to exit. * This is done so that interactive testing is easier. * * @param args (optional) filename to execute. Stored in the args variable. * * @throws Exception if parsing or IO fail */ public static void main(String[] args) throws Exception { JexlEngine engine = new JexlEngine(); JexlContext context = new MapContext(); context.set("args", args); if (args.length == 1) { Script script = engine.createScript(new File(args[0])); Object value = script.execute(context); System.out.println("Return value: " + value); } else { BufferedReader console = new BufferedReader(new InputStreamReader(System.in)); String line; System.out.print("> "); while (null != (line = console.readLine())) { try { Expression expression = engine.createExpression(line); Object value = expression.evaluate(context); System.out.println("Return value: " + value); } catch (JexlException e) { System.out.println(e.getLocalizedMessage()); } System.out.print("> "); } } } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/MapContext.java100644 0 0 3614 11673634324 24147 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.HashMap; import java.util.Map; /** * Wraps a map in a context. *

Each entry in the map is considered a variable name, value pair.

*/ public class MapContext implements JexlContext { /** * The wrapped variable map. */ protected final Map map; /** * Creates a MapContext on an automatically allocated underlying HashMap. */ public MapContext() { this(null); } /** * Creates a MapContext wrapping an existing user provided map. * @param vars the variable map */ public MapContext(Map vars) { super(); map = vars == null ? new HashMap() : vars; } /** {@inheritDoc} */ public boolean has(String name) { return map.containsKey(name); } /** {@inheritDoc} */ public Object get(String name) { return map.get(name); } /** {@inheritDoc} */ public void set(String name, Object value) { map.put(name, value); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/NamespaceResolver.java100644 0 0 3232 11673634323 25476 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * * This interface declares how to resolve a namespace from its name; it is used by the interpreter during evalutation. *

* In JEXL, a namespace is an object that serves the purpose of encapsulating functions; for instance, * the "math" namespace would be the proper object to expose functions like "log(...)", "sinus(...)", etc. *

* In expressions like "ns:function(...)", the resolver is called with resolveNamespace("ns"). *

* JEXL itself reserves 'jexl' and 'ujexl' as namespaces for internal purpose; resolving those may lead to unexpected * results. *

* @since 2.1 */ public interface NamespaceResolver { /** * Resolves a namespace by its name. * @param name the name * @return the namespace object */ Object resolveNamespace(String name); } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/ObjectContext.java100644 0 0 3556 11673634322 24643 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Wraps an Object as a Jexl context. * @param the wrapped object type to use * @since 2.1 */ public class ObjectContext implements JexlContext { /** The property solving jexl engine. */ private final JexlEngine jexl; /** The object serving as context provider. */ private final T object; /** * Creates a new ObjectContext. * @param engine the jexl engine to use to solve properties * @param wrapped the object to wrap in this context */ public ObjectContext(JexlEngine engine, T wrapped) { this.jexl = engine; this.object = wrapped; } /** {@inheritDoc} */ public Object get(String name) { return jexl.getProperty(object, name); } /** {@inheritDoc} */ public void set(String name, Object value) { jexl.setProperty(object, name, value); } /** {@inheritDoc} */ public boolean has(String name) { return jexl.getUberspect().getPropertyGet(object, name, null) != null; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/package.html100644 0 0 36056 11673634323 23530 0ustar 0 0 Package Documentation for org.apache.commons.jexl2 Package Provides a framework for evaluating JEXL expressions.

Introduction

JEXL is a library intended to facilitate the implementation of dynamic and scripting features in applications and frameworks.

A Brief Example

When evaluating expressions, JEXL merges an {@link org.apache.commons.jexl2.Expression} with a {@link org.apache.commons.jexl2.JexlContext}. An Expression is created using {@link org.apache.commons.jexl2.JexlEngine#createExpression(java.lang.String)}, passing a String containing valid JEXL syntax. A simple JexlContext can be created using a {@link org.apache.commons.jexl2.MapContext} instance; a map of variables that will be internally wrapped can be optionally provided through its constructor. The following example, takes a variable named foo, and invokes the bar() method on the property innerFoo:

            // Create a JexlEngine (could reuse one instead)
            JexlEngine jexl = new JexlEngine();
            // Create an expression object
            String jexlExp = "foo.innerFoo.bar()";
            Expression e = jexl.createExpression( jexlExp );

            // Create a context and add data
            JexlContext jc = new MapContext();
            jc.set("foo", new Foo() );

            // Now evaluate the expression, getting the result
            Object o = e.evaluate(jc);
        

Using JEXL

The API is composed of three levels addressing different functional needs:
  • Dynamic invocation of setters, getters, methods and constructors
  • Script expressions known as JEXL expressions
  • JSP/JSF like expression known as UnifiedJEXL expressions

Important note

The only public packages you should use are:
  • org.apache.commons.jexl2
  • org.apache.commons.jexl2.introspection
The following packages follow a "use at your own maintenance cost" policy. Their classes and methods are not guaranteed to remain compatible in subsequent versions. If you think you need to use some of their features, it might be a good idea to check with the community through the mailing list first.
  • org.apache.commons.jexl2.parser
  • org.apache.commons.jexl2.scripting
  • org.apache.commons.jexl2.internal
  • org.apache.commons.jexl2.internal.introspection

Dynamic invocation

These functionalities are close to the core level utilities found in BeanUtils. For basic dynamic property manipulations and method invocation, you can use the following set of methods:

  • {@link org.apache.commons.jexl2.JexlEngine#newInstance}
  • {@link org.apache.commons.jexl2.JexlEngine#setProperty}
  • {@link org.apache.commons.jexl2.JexlEngine#getProperty}
  • {@link org.apache.commons.jexl2.JexlEngine#invokeMethod}
The following example illustrate their usage:
            // test outer class
            public static class Froboz {
                int value;
                public Froboz(int v) { value = v; }
                public void setValue(int v) { value = v; }
                public int getValue() { return value; }
            }
            // test inner class
            public static class Quux {
                String str;
                Froboz froboz;
                public Quux(String str, int fro) {
                    this.str = str;
                    froboz = new Froboz(fro);
                }
                public Froboz getFroboz() { return froboz; }
                public void setFroboz(Froboz froboz) { this.froboz = froboz; }
                public String getStr() { return str; }
                public void setStr(String str) { this.str = str; }
            }
            // test API
            JexlEngine jexl = nex JexlEngine();
            Quux quux = jexl.newInstance(Quux.class, "xuuq", 100);
            jexl.setProperty(quux, "froboz.value", Integer.valueOf(100));
            Object o = jexl.getProperty(quux, "froboz.value");
            assertEquals("Result is not 100", new Integer(100), o);
            jexl.setProperty(quux, "['froboz'].value", Integer.valueOf(1000));
            o = jexl.getProperty(quux, "['froboz']['value']");
            assertEquals("Result is not 1000", new Integer(1000), o);
        

JEXL script expression

If your needs require simple expression evaluation capabilities, the core JEXL features will most likely fit. The main methods are:

  • {@link org.apache.commons.jexl2.JexlEngine#createExpression}
  • {@link org.apache.commons.jexl2.JexlEngine#createScript}
  • {@link org.apache.commons.jexl2.Expression#evaluate}
The following example illustrates their usage:
            JexlEngine jexl = nex JexlEngine();

            JexlContext jc = new MapContext();
            jc.set("quuxClass", quux.class);

            Expression create = jexl.createExpression("quux = new(quuxClass, 'xuuq', 100)");
            Expression assign = jexl.createExpression("quux.froboz.value = 10");
            Expression check = jexl.createExpression("quux[\"froboz\"].value");
            Quux quux = (Quux) create.evaluate(jc);
            Object o = assign.evaluate(jc);
            assertEquals("Result is not 10", new Integer(10), o);
            o = check.evaluate(jc);
            assertEquals("Result is not 10", new Integer(10), o);
        

UnifiedJEXL script expressions

If you are looking for JSP-EL like and basic templating features, you can use UnifiedJEXL.

The main methods are:
  • {@link org.apache.commons.jexl2.UnifiedJEXL#parse}
  • {@link org.apache.commons.jexl2.UnifiedJEXL.Expression#evaluate}
  • {@link org.apache.commons.jexl2.UnifiedJEXL.Expression#prepare}
The following example illustrates their usage:
            JexlEngine jexl = new JexlEngine();
            UnifiedJEXL ujexl = new UnifiedJEXL(jexl);
            UnifiedJEXL.Expression expr = ujexl.parse("Hello ${user}");
            String hello = expr.evaluate(context, expr).toString();
        

Expressions Script and UnifiedJEXL.Expression: differences

Expression

This only allows for a single command to be executed and the result from that is returned. If you try to use multiple commands it ignores everything after the first semi-colon and just returns the result from the first command.

Script

This allows you to put multiple commands in the expression and you can use variable assignments, loops, calculations, etc. The result from the last command is returned from the script.

UnifiedJEXL.Expression

This is ideal to produce text. To get a calculation you use the EL-like syntax as in ${someVariable}. The expression that goes between the brackets behaves like a script, not an expression. You can use semi-colons to execute multiple commands and the result from the last command is returned from the script. You also have the ability to use a 2-pass evaluation using the #{someScript} syntax.

JEXL Configuration

The JexlEngine can be configured through a few parameters that will drive how it reacts in case of errors. These configuration methods are best called at JEXL engine initialization time; it is recommended to derive from JexlEngine to call those in a constructor.

{@link org.apache.commons.jexl2.JexlEngine#setLenient} configures when JEXL considers 'null' as an error or not in various situations; when facing an unreferenceable variable, using null as an argument to an arithmetic operator or failing to call a method or constructor. The lenient mode is close to JEXL-1.1 behavior.

{@link org.apache.commons.jexl2.JexlEngine#setSilent} configures how JEXL reacts to errors; if silent, the engine will not throw exceptions but will warn through loggers and return null in case of errors. Note that when non-silent, JEXL throws JexlException which are unchecked exception.

{@link org.apache.commons.jexl2.JexlEngine#setDebug} makes stacktraces carried by JExlException more meaningfull; in particular, these traces will carry the exact caller location the Expression was created from.

{@link org.apache.commons.jexl2.JexlEngine#setClassLoader} indicates to a JexlEngine which class loader to use to solve a class name; this affects how JexlEngine.newInstance and the 'new' script method operates. This is mostly usefull in cases where you rely on JEXL to dynamically load and call plugins for your application.

JexlEngine and UnifiedJEXL expression caches can be configured as well. If you intend to use JEXL repeatedly in your application, these are worth configuring since expression parsing is quite heavy. Note that all caches created by JEXL are held through SoftReference; under high memory pressure, the GC will be able to reclaim those caches and JEXL will rebuild them if needed. By default, a JexlEngine does not create a cache whilst UnifiedJEXL does.

Both JexlEngine and UnifiedJEXL are thread-safe; the same instance can be shared between different threads and proper synchronization is enforced in critical areas.

{@link org.apache.commons.jexl2.JexlEngine#setCache} will set how many expressions can be simultaneously cached by the JEXL engine. UnifiedJEXL allows to define the cache size through its constructor.

{@link org.apache.commons.jexl2.JexlEngine#setFunctions} extends JEXL scripting by registering functions in namespaces.

This can be used as in:

            public static MyMath {
                public double cos(double x) {
                    return Math.cos(x);
                }
            }
            Map<String, Object> funcs = new HashMap<String, Object>();
            funcs.put("math", new MyMath());
            JexlEngine jexl = new JexlEngine();
            jexl.setFunctions(funcs);

            JexlContext jc = new MapContext();
            jc.set("pi", Math.PI);

            e = JEXL.createExpression("math:cos(pi)");
            o = e.evaluate(jc);
            assertEquals(Double.valueOf(-1),o);
        
If the namespace is a Class and that class declares a constructor that takes a JexlContext (or a class extending JexlContext), one namespace instance is created on first usage in an expression; this instance lifetime is limited to the expression evaluation.

JEXL Customization

If you need to make JEXL treat some objects in a specialized manner or tweak how it reacts to some settings, you can derive most of its inner-workings.

{@link org.apache.commons.jexl2.JexlEngine} is meant to be extended and lets you capture your own configuration defaults wrt cache sizes and various flags. Implementing your own cache - instead of the basic LinkedHashMap based one - would be another possible extension.

{@link org.apache.commons.jexl2.JexlArithmetic} is the class to derive if you need to change how operators behave. For example, this would be the case if you wanted '+' to operate on arrays; you'd need to derive JexlArithmetic and implement your own version of Add.

{@link org.apache.commons.jexl2.Interpreter} is the class to derive if you need to add more features to the evaluation itself; for instance, you want pre- and post- resolvers for variables or nested scopes for for variable contexts or add factory based support to the 'new' operator.

{@link org.apache.commons.jexl2.introspection.UberspectImpl} is the class to derive if you need to add introspection or reflection capabilities for some objects. The code already reflects public fields as properties on top of Java-beans conventions.

commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ASTArrayLiteral.java100644 0 0 4455 11673634323 26327 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; public final class ASTArrayLiteral extends JexlNode implements JexlNode.Literal { /** The type literal value. */ Object array = null; /** Whether this array is constant or not. */ boolean constant = false; ASTArrayLiteral(int id) { super(id); } ASTArrayLiteral(Parser p, int id) { super(p, id); } /** {@inheritDoc} */ @Override public void jjtClose() { if (children == null || children.length == 0) { array = new Object[0]; constant = true; } else { constant = isConstant(); } } /** * Gets the literal value. * @return the array literal */ public Object getLiteral() { return array; } /** * Sets the literal value only if the descendants of this node compose a constant * @param literal the literal array value * @throws IllegalArgumentException if literal is not an array or null */ public void setLiteral(Object literal) { if (constant) { if (literal != null && !literal.getClass().isArray()) { throw new IllegalArgumentException(literal.getClass() + " is not an array"); } this.array = literal; } } /** {@inheritDoc} */ @Override public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ASTFloatLiteral.java100644 0 0 3134 11673634323 26307 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; /** * @deprecated Only for use in maintaining binary compatibility - should not actually be used - will be removed in 3.0 */ @Deprecated public final class ASTFloatLiteral extends JexlNode implements JexlNode.Literal { /** The type literal value. */ Float literal = null; public ASTFloatLiteral(int id) { super(id); } public ASTFloatLiteral(Parser p, int id) { super(p, id); } /** * Gets the literal value. * @return the float literal */ public Float getLiteral() { return literal; } /** {@inheritDoc} */ @Override public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ASTIdentifier.java100644 0 0 3031 11673634323 26003 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; /** * Identifiers, variables and registers. */ public class ASTIdentifier extends JexlNode { private int register = -1; public ASTIdentifier(int id) { super(id); } public ASTIdentifier(Parser p, int id) { super(p, id); } void setRegister(String r) { if (r.charAt(0) == '#') { register = Integer.parseInt(r.substring(1)); } } void setRegister(int r) { register = r; } public int getRegister() { return register; } @Override public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ASTIntegerLiteral.java100644 0 0 3130 11673634323 26633 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; /** * @deprecated Only for use in maintaining binary compatibility - should not actually be used - will be removed in 3.0 */ @Deprecated public final class ASTIntegerLiteral extends JexlNode implements JexlNode.Literal { /** The type literal value. */ Integer literal = null; ASTIntegerLiteral(int id) { super(id); } ASTIntegerLiteral(Parser p, int id) { super(p, id); } /** * Gets the literal value. * @return the integer literal */ public Integer getLiteral() { return literal; } /** {@inheritDoc} */ @Override public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ASTJexlScript.java100644 0 0 5661 11673634323 26023 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; import org.apache.commons.jexl2.JexlEngine; /** * Enhanced script to allow parameters declaration. */ public class ASTJexlScript extends JexlNode { /** The script scope. */ private JexlEngine.Scope scope = null; public ASTJexlScript(int id) { super(id); } public ASTJexlScript(Parser p, int id) { super(p, id); } @Override public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } /** * Sets the parameters and registers * @param theScope the scope */ public void setScope(JexlEngine.Scope theScope) { this.scope = theScope; } /** * Gets this script scope. */ public JexlEngine.Scope getScope() { return scope; } /** * Creates an array of arguments by copying values up to the number of parameters. * @param values the argument values * @return the arguments array */ public JexlEngine.Frame createFrame(Object... values) { return scope != null? scope.createFrame(values) : null; } /** * Gets the (maximum) number of arguments this script expects. * @return the number of parameters */ public int getArgCount() { return scope != null? scope.getArgCount() : 0; } /** * Gets this script registers, i.e. parameters and local variables. * @return the register names */ public String[] getRegisters() { return scope != null? scope.getRegisters() : null; } /** * Gets this script parameters, i.e. registers assigned before creating local variables. * @return the parameter names */ public String[] getParameters() { return scope != null? scope.getParameters() : null; } /** * Gets this script local variable, i.e. registers assigned to local variables. * @return the parameter names */ public String[] getLocalVariables() { return scope != null? scope.getLocalVariables() : null; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ASTMapLiteral.java100644 0 0 4532 11673634323 25762 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; import java.util.Collections; import java.util.Map; public final class ASTMapLiteral extends JexlNode implements JexlNode.Literal { /** The type literal value. */ Map map = null; /** Whether this array is constant or not. */ boolean constant = false; ASTMapLiteral(int id) { super(id); } ASTMapLiteral(Parser p, int id) { super(p, id); } /** {@inheritDoc} */ @Override public void jjtClose() { if (children == null || children.length == 0) { map = Collections.EMPTY_MAP; constant = true; } else { constant = isConstant(); } } /** * Gets the literal value. * @return the array literal */ public Object getLiteral() { return map; } /** * Sets the literal value only if the descendants of this node compose a constant * @param literal the literal array value * @throws IllegalArgumentException if literal is not an array or null */ public void setLiteral(Object literal) { if (constant) { if (!(literal instanceof Map)) { throw new IllegalArgumentException(literal.getClass() + " is not an array"); } this.map = (Map) literal; } } /** {@inheritDoc} */ @Override public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ASTNumberLiteral.java100644 0 0 11207 11673634323 26512 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; import java.math.BigDecimal; import java.math.BigInteger; public class ASTNumberLiteral extends JexlNode implements JexlNode.Literal { /** The type literal value. */ Number literal = null; /** The expected class. */ Class clazz = null; public ASTNumberLiteral(int id) { super(id); } public ASTNumberLiteral(Parser p, int id) { super(p, id); } /** * Gets the literal value. * @return the number literal */ public Number getLiteral() { return literal; } /** {@inheritDoc} */ @Override protected boolean isConstant(boolean literal) { return true; } /** {@inheritDoc} */ @Override public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } public Class getLiteralClass() { return clazz; } public boolean isInteger() { return Integer.class.equals(clazz); } /** * Sets this node as a natural literal. * Originally from OGNL. * @param s the natural as string */ public void setNatural(String s) { Number result; Class rclass; // determine the base final int base; if (s.charAt(0) == '0') { if ((s.length() > 1 && (s.charAt(1) == 'x' || s.charAt(1) == 'X'))) { base = 16; s = s.substring(2); // Trim the 0x off the front } else { base = 8; } } else { base = 10; } final int last = s.length() - 1; switch (s.charAt(last)) { case 'l': case 'L': { rclass = Long.class; result = Long.valueOf(s.substring(0, last), base); break; } case 'h': case 'H': { rclass = BigInteger.class; result = new BigInteger(s.substring(0, last), base); break; } default: { rclass = Integer.class; try { result = Integer.valueOf(s, base); } catch (NumberFormatException take2) { try { result = Long.valueOf(s, base); } catch (NumberFormatException take3) { result = new BigInteger(s, base); } } } } literal = result; clazz = rclass; } /** * Sets this node as a real literal. * Originally from OGNL. * @param s the real as string */ public void setReal(String s) { Number result; Class rclass; final int last = s.length() - 1; switch (s.charAt(last)) { case 'b': case 'B': { result = new BigDecimal(s.substring(0, last)); rclass = BigDecimal.class; break; } case 'd': case 'D': { rclass = Double.class; result = Double.valueOf(s); break; } case 'f': case 'F': default: { rclass = Float.class; try { result = Float.valueOf(s); } catch (NumberFormatException take2) { try { result = Double.valueOf(s); } catch (NumberFormatException take3) { result = new BigDecimal(s); } } break; } } literal = result; clazz = rclass; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ASTReferenceExpression.java100644 0 0 2354 11673634323 27706 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; public final class ASTReferenceExpression extends ASTArrayAccess { public ASTReferenceExpression(int id) { super(id); } public ASTReferenceExpression(Parser p, int id) { super(p, id); } /** Accept the visitor. **/ @Override public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ASTStringLiteral.java100644 0 0 3017 11673634323 26510 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; public final class ASTStringLiteral extends JexlNode implements JexlNode.Literal { public ASTStringLiteral(int id) { super(id); } public ASTStringLiteral(Parser p, int id) { super(p, id); } /** * Gets the literal value. * @return the string literal */ public String getLiteral() { return image; } /** {@inheritDoc} */ @Override protected boolean isConstant(boolean literal) { return true; } /** {@inheritDoc} */ @Override public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ASTVar.java100644 0 0 2301 11673634323 24450 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; /** * Declares a local variable. */ public class ASTVar extends ASTIdentifier { public ASTVar(int id) { super(id); } public ASTVar(Parser p, int id) { super(p, id); } @Override public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/JexlNode.java100644 0 0 6065 11673634323 25073 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; import org.apache.commons.jexl2.DebugInfo; import org.apache.commons.jexl2.JexlInfo; /** * Base class for parser nodes - holds an 'image' of the token for later use. * * @since 2.0 */ public abstract class JexlNode extends SimpleNode implements JexlInfo { /** A marker interface for literals. * @param the literal type */ public interface Literal { T getLiteral(); } /** token value. */ public String image; public JexlNode(int id) { super(id); } public JexlNode(Parser p, int id) { super(p, id); } /** {@inheritDoc} */ public DebugInfo debugInfo() { JexlNode node = this; while (node != null) { if (node.value instanceof DebugInfo) { return (DebugInfo) node.value; } node = node.jjtGetParent(); } return null; } /** {@inheritDoc} */ public String debugString() { DebugInfo info = debugInfo(); return info != null ? info.debugString() : ""; } /** * Whether this node is a constant node * Its value can not change after the first evaluation and can be cached indefinitely. * @return true if constant, false otherwise */ public final boolean isConstant() { return isConstant(this instanceof JexlNode.Literal); } protected boolean isConstant(boolean literal) { if (literal) { if (children != null) { for (JexlNode child : children) { if (child instanceof ASTReference) { boolean is = child.isConstant(true); if (!is) { return false; } } else if (child instanceof ASTMapEntry) { boolean is = child.isConstant(true); if (!is) { return false; } } else if (!child.isConstant()) { return false; } } } return true; } return false; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/JexlParser.java100644 0 0 10471 11673634323 25456 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; import org.apache.commons.jexl2.DebugInfo; import org.apache.commons.jexl2.JexlEngine; import org.apache.commons.jexl2.JexlException; /** * The base class for parsing, manages the parameter/local variable frame. * @author henri */ public class JexlParser extends StringParser { /** * The map of named registers aka script parameters. * Each parameter is associated to a register and is materialized as an offset in the registers array used * during evaluation. */ protected JexlEngine.Scope frame; /** * Sets the frame to use bythis parser. *

* This is used to allow parameters to be declared before parsing. *

* @param theFrame the register map */ public void setFrame(JexlEngine.Scope theFrame) { frame = theFrame; } /** * Gets the frame used by this parser. *

* Since local variables create new named registers, it is important to regain access after * parsing to known which / how-many registers are needed. *

* @return the named register map */ public JexlEngine.Scope getFrame() { return frame; } /** * Checks whether an identifier is a local variable or argument, ie stored in a register. * @param identifier the identifier * @param image the identifier image * @return the image */ public String checkVariable(ASTIdentifier identifier, String image) { if (frame != null) { Integer register = frame.getRegister(image); if (register != null) { identifier.setRegister(register.intValue()); } } return image; } /** * Declares a local variable. *

* This method creates an new entry in the named register map. *

* @param identifier the identifier used to declare * @param image the variable name */ public void declareVariable(ASTVar identifier, String image) { if (frame == null) { frame = new JexlEngine.Scope((String[])null); } Integer register = frame.declareVariable(image); identifier.setRegister(register.intValue()); identifier.image = image; } /** * Default implementation does nothing but is overriden by generated code. * @param top whether the identifier is beginning an l/r value * @throws ParseException subclasses may throw this */ public void Identifier(boolean top) throws ParseException { // Overriden by generated code } final public void Identifier() throws ParseException { Identifier(false); } public Token getToken(int index) { return null; } void jjtreeOpenNodeScope(JexlNode n) { } /** * Ambiguous statement detector. * @param n the node * @throws ParseException */ void jjtreeCloseNodeScope(JexlNode n) throws ParseException { if (n instanceof ASTAmbiguous && n.jjtGetNumChildren() > 0) { DebugInfo dbgInfo = null; Token tok = this.getToken(0); if (tok != null) { dbgInfo = new DebugInfo(tok.image, tok.beginLine, tok.beginColumn); } else { dbgInfo = n.debugInfo(); } throw new JexlException.Parsing(dbgInfo, "Ambiguous statement, missing ';' between expressions", null); } } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/package.html100644 0 0 2511 11673634323 24771 0ustar 0 0 Package Documentation for org.apache.commons.jexl2.parser Package

Contains the Parser for JEXL script.

This internal package is not intended for public usage and there is no guarantee that its public classes or methods will remain as is in subsequent versions.

commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/ParseException.java100644 0 0 6254 11673634323 26314 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; /** * This exception is thrown when parse errors are encountered. */ public class ParseException extends Exception { /** * The version identifier. */ private static final long serialVersionUID = 1L; /** * Last correct input before error occurs. */ private String after = ""; /** * Error line. */ private int line = -1; /** * Error column. */ private int column = -1; /** * Gets the line number. * @return line number. */ public int getLine() { return line; } /** * Gets the column number. * @return the column. */ public int getColumn() { return column; } /** * Gets the last correct input. * @return the string after which the error occured */ public String getAfter() { return after; } /** * This constructor is used by the method "generateParseException" * in the generated parser. Calling this constructor generates * a new object of this type with the fields "currentToken", * "expectedTokenSequences", and "tokenImage" set. * @param currentToken This is the last token that has been consumed successfully. If * this object has been created due to a parse error, the token * followng this token will (therefore) be the first error token. * @param expectedTokenSequences Each entry in this array is an array of integers. Each array * of integers represents a sequence of tokens (by their ordinal * values) that is expected at this point of the parse. * @param tokenImage This is a reference to the "tokenImage" array of the generated * parser within which the parse error occurred. This array is * defined in the generated ...Constants interface. */ public ParseException(Token currentToken, int[][] expectedTokenSequences, String[] tokenImage) { super("parse error"); Token tok = currentToken.next; after = tok.image; line = tok.beginLine; column = tok.beginColumn; } /** * Default ctor. */ public ParseException() { super(); } /** Constructor with message. */ public ParseException(String message) { super(message); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/Parser.jjt100644 0 0 30672 11673634323 24506 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ options { MULTI=true; STATIC=false; VISITOR=true; NODE_SCOPE_HOOK=true; NODE_CLASS="JexlNode"; UNICODE_INPUT=true; } PARSER_BEGIN(Parser) package org.apache.commons.jexl2.parser; import java.io.Reader; import org.apache.commons.jexl2.JexlInfo; public class Parser extends JexlParser { public boolean ALLOW_REGISTERS = false; public ASTJexlScript parse(Reader reader, JexlInfo info) throws ParseException { /* * If registers are allowed, the default parser state has to be REGISTERS. */ if (ALLOW_REGISTERS) { token_source.defaultLexState = REGISTERS; } ReInit(reader); /* * lets do the 'Unique Init' in here to be * safe - it's a pain to remember */ ASTJexlScript tree = JexlScript(); tree.value = info; return tree; } } PARSER_END(Parser) /*************************************** * Skip & Number literal tokens ***************************************/ <*> SKIP : /* WHITE SPACE */ { <"##" (~["\n","\r"])* ("\n" | "\r" | "\r\n")? > | <"/*" (~["*"])* "*" ("*" | ~["*","/"] (~["*"])* "*")* "/"> | <"//" (~["\n","\r"])* ("\n" | "\r" | "\r\n")? > | " " | "\t" | "\n" | "\r" | "\f" } <*> TOKEN : /* KEYWORDS */ { < IF : "if" > | < ELSE : "else" > | < FOR : "for" > | < FOREACH : "foreach" > : FOR_EACH_IN | < WHILE : "while" > | < NEW : "new" > | < VAR : "var" > | < EMPTY : "empty" > | < SIZE : "size" > | < NULL : "null" > | < TRUE : "true" > | < FALSE : "false" > | < RETURN : "return" > } TOKEN : /* foreach in */ { < IN : "in" > : DEFAULT } <*> TOKEN : { /* SEPARATORS */ < LPAREN : "(" > | < RPAREN : ")" > | < LCURLY : "{" > | < RCURLY : "}" > | < LBRACKET : "[" > | < RBRACKET : "]" > | < SEMICOL : ";" > | < COLON : ":" > | < COMMA : "," > | < DOT : "." > } <*> TOKEN : { /* CONDITIONALS */ < QMARK : "?" > | < ELVIS : "?:" > | < AND : "&&" | "and" > | < OR : "||" | "or" > } <*> TOKEN : { /* COMPARISONS */ < eq : "==" | "eq" > | < ne : "!=" | "ne" > | < req : "=~" > | < rne : "!~" > | < gt : ">" | "gt" > | < ge : ">=" | "ge" > | < lt : "<" | "lt" > | < le : "<=" | "le" > } <*> TOKEN : { /* OPERATORS */ < assign : "=" > | < mod : "%" | "mod" > | < div : "/" | "div" > | < not : "!" | "not" > | < plus : "+" > | < minus : "-" > | < mult : "*" > | < tilda : "~" > | < and : "&" > | < or : "|" > | < xor : "^" > } /*************************************** * Identifier & String tokens ***************************************/ <*> TOKEN : /* IDENTIFIERS */ { < IDENTIFIER: (|)* > | < #LETTER: [ "a"-"z", "A"-"Z", "_", "$", "@" ] > | < #DIGIT: [ "0"-"9"] > } TOKEN : /* REGISTERS: parser.ALLOW_REGISTER must be set to true before calling parse */ { < REGISTER: "#" (["0"-"9"])+ > } <*> TOKEN : /* LITERALS */ { < INTEGER_LITERAL: ( "0" (["0"-"7"])* | ["1"-"9"] (["0"-"9"])* | "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ ) (["l","L","h","H"])? > | < FLOAT_LITERAL: ()+ "." ()+ ((["e","E"])(["+","-"])?()+)? (["d","D","f","F","b","B"])? > } <*> TOKEN : { < STRING_LITERAL: "\"" (~["\"","\\","\n","\r","\u2028","\u2029"] | "\\" ~["\n","\r","\u2028","\u2029"])* "\"" | "'" (~["'","\\","\n","\r","\u2028","\u2029"] | "\\" ~["\n","\r","\u2028","\u2029"])* "'" > } /*************************************** * Statements ***************************************/ ASTJexlScript JexlScript() : {} { ( Statement() )* { return jjtThis;} } void Statement() #void : {} { | LOOKAHEAD(3) Block() | IfStatement() | ForeachStatement() | WhileStatement() | ExpressionStatement() | ReturnStatement() | Var() } void Block() #Block : {} { ( Statement() )* } void ExpressionStatement() #void : {} { Expression() (LOOKAHEAD(1) Expression() #Ambiguous())* (LOOKAHEAD(2) )? } void IfStatement() : {} { Expression() Statement() ( LOOKAHEAD(1) Statement() )? } void WhileStatement() : {} { Expression() Statement() } void ForeachStatement() : {} { LValueVar() Expression() Statement() | LValueVar() Expression() Statement() } void ReturnStatement() : {} { Expression() } /*************************************** * Expression syntax ***************************************/ void Expression() #void : {} { ConditionalExpression() (LOOKAHEAD(1) Expression() #Assignment(2) )? } void Assignment() #Assignment(2) : {} { ConditionalExpression() Expression() } void Var() #void : {} { DeclareVar() (LOOKAHEAD(1) Expression() #Assignment(2))? } void DeclareVar() #Var : { Token t; } { t= { declareVariable(jjtThis, t.image); } } void LValueVar() #Reference : {} { LOOKAHEAD(1) DeclareVar() DotReference() | LOOKAHEAD(1) Identifier(true) DotReference() } /*************************************** * Conditional & relational ***************************************/ void ConditionalExpression() #void : {} { ConditionalOrExpression() ( Expression() Expression() #TernaryNode(3) | Expression() #TernaryNode(2) )? } void ConditionalOrExpression() #void : {} { ConditionalAndExpression() ( ConditionalAndExpression() #OrNode(2) )* } void ConditionalAndExpression() #void : {} { InclusiveOrExpression() ( InclusiveOrExpression() #AndNode(2) )* } void InclusiveOrExpression() #void : {} { ExclusiveOrExpression() ( ExclusiveOrExpression() #BitwiseOrNode(2) )* } void ExclusiveOrExpression() #void : {} { AndExpression() ( AndExpression() #BitwiseXorNode(2) )* } void AndExpression() #void : {} { EqualityExpression() ( EqualityExpression() #BitwiseAndNode(2) )* } void EqualityExpression() #void : {} { RelationalExpression() ( RelationalExpression() #EQNode(2) | RelationalExpression() #NENode(2) )? } void RelationalExpression() #void : {} { AdditiveExpression() ( AdditiveExpression() #LTNode(2) | AdditiveExpression() #GTNode(2) | AdditiveExpression() #LENode(2) | AdditiveExpression() #GENode(2) | AdditiveExpression() #ERNode(2) // equals regexp | AdditiveExpression() #NRNode(2) // not equals regexp )? } /*************************************** * Arithmetic ***************************************/ void AdditiveExpression() #AdditiveNode(>1) : {} { MultiplicativeExpression() ( LOOKAHEAD(1) AdditiveOperator() MultiplicativeExpression())* } void AdditiveOperator() : {} { { jjtThis.image = "+"; } | { jjtThis.image = "-"; } } void MultiplicativeExpression() #void : {} { UnaryExpression() ( UnaryExpression() #MulNode(2) |
UnaryExpression() #DivNode(2) | UnaryExpression() #ModNode(2) )* } void UnaryExpression() #void : {} { UnaryExpression() #UnaryMinusNode(1) | UnaryExpression() #BitwiseComplNode(1) | UnaryExpression() #NotNode(1) | PrimaryExpression() } /*************************************** * Identifier & Literals ***************************************/ void Identifier(boolean top) : { Token t; } { t= { jjtThis.image = top? checkVariable(jjtThis, t.image) : t.image; } | t= { jjtThis.image = t.image; jjtThis.setRegister(t.image); } } void StringIdentifier() #Identifier : { Token t; } { t= { jjtThis.image = Parser.buildString(t.image, true); } } void Literal() #void : { Token t; } { IntegerLiteral() | FloatLiteral() | BooleanLiteral() | StringLiteral() | NullLiteral() } void NullLiteral() : {} { } void BooleanLiteral() #void : {} { #TrueNode | #FalseNode } void IntegerLiteral() #NumberLiteral : { Token t; } { t= { jjtThis.image = t.image; jjtThis.setNatural(t.image); } } void FloatLiteral() #NumberLiteral: { Token t; } { t= { jjtThis.image = t.image; jjtThis.setReal(t.image); } } void StringLiteral() : { Token t; } { t= { jjtThis.image = Parser.buildString(t.image, true); } } void ArrayLiteral() : {} { (Expression() ( Expression() )*)? } void MapLiteral() : {} { ( MapEntry() ( MapEntry() )* | ) } void MapEntry() : {} { Expression() Expression() } /*************************************** * Functions & Methods ***************************************/ void EmptyFunction() : {} { LOOKAHEAD(3) Expression() | Reference() } void SizeFunction() : {} { Expression() } void Function() #FunctionNode: {} { Identifier() Identifier() [ Expression() ( Expression() )* ] } void Method() #MethodNode: {} { Identifier() [ Expression() ( Expression() )* ] } void AnyMethod() #void : {} { LOOKAHEAD() SizeMethod() | LOOKAHEAD(Identifier() ) Method() } void SizeMethod() : {} { } void Constructor() #ConstructorNode() : {} { [ Expression() ( Expression() )* ] } /*************************************** * References ***************************************/ void PrimaryExpression() #void : {} { LOOKAHEAD(2) Reference() | LOOKAHEAD( ) EmptyFunction() | LOOKAHEAD( ) SizeFunction() | LOOKAHEAD( ) Constructor() | LOOKAHEAD( (Expression())? ) MapLiteral() | LOOKAHEAD( (Expression() | ) ) ArrayLiteral() | Literal() } void ArrayAccess() : {} { Identifier() (LOOKAHEAD(1) Expression() )+ } void DotReference() #void : {} { ( ( LOOKAHEAD(Identifier() ) ArrayAccess() | ( LOOKAHEAD(2) AnyMethod() | Identifier() | IntegerLiteral() | StringIdentifier() ) ) )* } void Reference() : {} { ( LOOKAHEAD() Constructor() | LOOKAHEAD(Identifier() ) ArrayAccess() | LOOKAHEAD(Identifier() Identifier() ) Function() | LOOKAHEAD(Identifier() ) Method() | LOOKAHEAD() MapLiteral() | LOOKAHEAD() ArrayLiteral() | LOOKAHEAD( Expression() ) ReferenceExpression() | StringLiteral() | Identifier(true) ) DotReference() } /** * ReferenceExpression is a subclass of ArrayAccess */ void ReferenceExpression() : {} { Expression() (LOOKAHEAD(1) Expression() )* } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/SimpleNode.java100644 0 0 13215 11673634323 25435 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; /** * A class originally generated by JJTree with the following JavaCCOptions: * MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY= * * Works around issue https://javacc.dev.java.net/issues/show_bug.cgi?id=227 * As soon as this issue if fixed and the maven plugin uses the correct version of Javacc, this * class can go away. * * The technical goal is to ensure every reference made in the parser was to a JexlNode; unfortunately, * as in javacc 4.1, it still uses a SimpleNode reference in the generated ParserVisitor. * Besides, there is no need to keep the parser around in the node. * * The functional goal is to a allow a volatile value in the node * so it can serve as a last evaluation cache even in multi-threaded executions. */ public class SimpleNode implements Node { /** The parent node. */ protected JexlNode parent; /** The array of children nodes. */ protected JexlNode[] children; /** The node type id. */ protected final int id; /** volatile value so it can be used as a last evaluation cache. */ protected volatile Object value; /** * Creates a SimpleNode instance. * @param i the node type identifier */ public SimpleNode(int i) { id = i; } /** * Creates a SimpleNode instance. * @param p the parser instance * @param i the node type identifier */ public SimpleNode(Parser p, int i) { this(i); } /** {@inheritDoc} */ public void jjtOpen() { } /** {@inheritDoc} */ public void jjtClose() { } /** * Sets this node's parent. * @param n the parent */ public void jjtSetParent(Node n) { parent = (JexlNode) n; } /** * Gets this node's parent. * @return the parent node */ public JexlNode jjtGetParent() { return parent; } /** Adds a child node. * @param n the child node * @param i the child offset */ public void jjtAddChild(Node n, int i) { if (children == null) { children = new JexlNode[i + 1]; } else if (i >= children.length) { JexlNode[] c = new JexlNode[i + 1]; System.arraycopy(children, 0, c, 0, children.length); children = c; } children[i] = (JexlNode) n; } /** * Gets a child of this node. * @param i the child offset * @return the child node */ public JexlNode jjtGetChild(int i) { return children[i]; } /** * Gets this node number of children. * @return the number of children */ public int jjtGetNumChildren() { return (children == null) ? 0 : children.length; } /** Sets this node value. * @param value */ public void jjtSetValue(Object value) { this.value = value; } /** Gets this node value. * @return value */ public Object jjtGetValue() { return value; } /** * Accept the visitor. * @param visitor the visitor * @param data contextual data * @return result of visit **/ public Object jjtAccept(ParserVisitor visitor, Object data) { return visitor.visit(this, data); } /** * Accept the visitor on all this node's children. * @param visitor the visitor * @param data contextual data * @return result of visit **/ public Object childrenAccept(ParserVisitor visitor, Object data) { if (children != null) { for (int i = 0; i < children.length; ++i) { children[i].jjtAccept(visitor, data); } } return data; } /* You can override these two methods in subclasses of SimpleNode to customize the way the JexlNode appears when the tree is dumped. If your output uses more than one line you should override toString(String), otherwise overriding toString() is probably all you need to do. */ @Override public String toString() { return ParserTreeConstants.jjtNodeName[id]; } public String toString(String prefix) { return prefix + toString(); } /* Override this method if you want to customize how the JexlNode dumps out its children. */ public void dump(String prefix) { System.out.println(toString(prefix)); if (children != null) { for (int i = 0; i < children.length; ++i) { SimpleNode n = children[i]; if (n != null) { n.dump(prefix + " "); } } } } } /* JavaCC - OriginalChecksum=7dff880883d088a37c1e3197e4b455a0 (do not edit this line) */ commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/StringParser.java100644 0 0 17610 11673634323 26024 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; /** * Common constant strings utilities. *

* This package methods read JEXL string literals and handle escaping through the * 'backslash' (ie: \) character. Escaping is used to neutralize string delimiters (the single * and double quotes) and read Unicode hexadecimal encoded characters. *

*

* The only escapable characters are the single and double quotes - ''' and '"' -, * a Unicode sequence starting with 'u' followed by 4 hexadecimals and * the backslash character - '\' - itself. *

*

* A sequence where '\' occurs before any non-escapable character or sequence has no effect, the * sequence output being the same as the input. *

*/ public class StringParser { /** Default constructor. */ public StringParser() { } /** * Builds a string, handles escaping through '\' syntax. * @param str the string to build from * @param eatsep whether the separator, the first character, should be considered * @return the built string */ public static String buildString(CharSequence str, boolean eatsep) { StringBuilder strb = new StringBuilder(str.length()); char sep = eatsep ? str.charAt(0) : 0; int end = str.length() - (eatsep ? 1 : 0); int begin = (eatsep ? 1 : 0); read(strb, str, begin, end, sep); return strb.toString(); } /** * Read the remainder of a string till a given separator, * handles escaping through '\' syntax. * @param strb the destination buffer to copy characters into * @param str the origin * @param index the offset into the origin * @param sep the separator, single or double quote, marking end of string * @return the offset in origin */ public static int readString(StringBuilder strb, CharSequence str, int index, char sep) { return read(strb, str, index, str.length(), sep); } /** The length of an escaped unicode sequence. */ private static final int UCHAR_LEN = 4; /** * Read the remainder of a string till a given separator, * handles escaping through '\' syntax. * @param strb the destination buffer to copy characters into * @param str the origin * @param begin the relative offset in str to begin reading * @param end the relative offset in str to end reading * @param sep the separator, single or double quote, marking end of string * @return the last character offset handled in origin */ private static int read(StringBuilder strb, CharSequence str, int begin, int end, char sep) { boolean escape = false; int index = begin; for (; index < end; ++index) { char c = str.charAt(index); if (escape) { if (c == 'u' && (index + UCHAR_LEN) < end && readUnicodeChar(strb, str, index + 1) > 0) { index += UCHAR_LEN; } else { // if c is not an escapable character, re-emmit the backslash before it boolean notSeparator = sep == 0 ? c != '\'' && c != '"' : c != sep; if (notSeparator && c != '\\') { strb.append('\\'); } strb.append(c); } escape = false; continue; } if (c == '\\') { escape = true; continue; } strb.append(c); if (c == sep) { break; } } return index; } /** Initial shift value for composing a Unicode char from 4 nibbles (16 - 4). */ private static final int SHIFT = 12; /** The base 10 offset used to convert hexa characters to decimal. */ private static final int BASE10 = 10; /** * Reads a Unicode escape character. * @param strb the builder to write the character to * @param str the sequence * @param begin the begin offset in sequence (after the '\\u') * @return 0 if char could not be read, 4 otherwise */ private static int readUnicodeChar(StringBuilder strb, CharSequence str, int begin) { char xc = 0; int bits = SHIFT; int value = 0; for (int offset = 0; offset < UCHAR_LEN; ++offset) { char c = str.charAt(begin + offset); if (c >= '0' && c <= '9') { value = (c - '0'); } else if (c >= 'a' && c <= 'h') { value = (c - 'a' + BASE10); } else if (c >= 'A' && c <= 'H') { value = (c - 'A' + BASE10); } else { return 0; } xc |= value << bits; bits -= UCHAR_LEN; } strb.append(xc); return UCHAR_LEN; } /** The last 7bits ascii character. */ private static final char LAST_ASCII = 127; /** The first printable 7bits ascii character. */ private static final char FIRST_ASCII = 32; /** * Escapes a String representation, expand non-ASCII characters as Unicode escape sequence. * @param str the string to escape * @return the escaped representation */ public static String escapeString(String str, char delim) { if (str == null) { return null; } final int length = str.length(); StringBuilder strb = new StringBuilder(length + 2); strb.append(delim); for (int i = 0; i < length; ++i) { char c = str.charAt(i); switch (c) { case 0: continue; case '\b': strb.append("\\b"); break; case '\t': strb.append("\\t"); break; case '\n': strb.append("\\n"); break; case '\f': strb.append("\\f"); break; case '\r': strb.append("\\r"); break; case '\"': strb.append("\\\""); break; case '\'': strb.append("\\\'"); break; case '\\': strb.append("\\\\"); break; default: if (c >= FIRST_ASCII && c <= LAST_ASCII) { strb.append(c); } else { // convert to Unicode escape sequence strb.append('\\'); strb.append('u'); String hex = Integer.toHexString(c); for (int h = hex.length(); h < UCHAR_LEN; ++h) { strb.append('0'); } strb.append(hex); } } } strb.append(delim); return strb.toString(); } }commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/parser/TokenMgrError.java100644 0 0 10110 11673634323 26125 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; /** * Token Manager Error. */ public class TokenMgrError extends Error { /** * The version identifier for this Serializable class. * Increment only if the serialized form of the * class changes. */ private static final long serialVersionUID = 1L; /* * Ordinals for various reasons why an Error of this type can be thrown. */ /** * Lexical error occurred. */ public static final int LEXICAL_ERROR = 0; /** * An attempt was made to create a second instance of a static token manager. */ public static final int STATIC_LEXER_ERROR = 1; /** * Tried to change to an invalid lexical state. */ public static final int INVALID_LEXICAL_STATE = 2; /** * Detected (and bailed out of) an infinite loop in the token manager. */ public static final int LOOP_DETECTED = 3; /** * Indicates the reason why the exception is thrown. It will have * one of the above 4 values. */ private int errorCode; /** * The lexer state. */ @SuppressWarnings("unused") // not read currently private int state; /** * The current character. */ private char current; /** * Last correct input before error occurs. */ private String after; /** * */ private boolean eof; /** * Error line. */ private int line; /** * Error column. */ private int column; /** * Gets the reason why the exception is thrown. * @return one of the 4 lexical error codes */ public int getErrorCode() { return errorCode; } /** * Gets the line number. * @return line number. */ public int getLine() { return line; } /** * Gets the column number. * @return the column. */ public int getColumn() { return column; } /** * Gets the last correct input. * @return the string after which the error occured */ public String getAfter() { return after; } /** * Returns a detailed message for the Error when it is thrown by the * token manager to indicate a lexical error. * @return the message */ @Override public String getMessage() { return ("Lexical error at line " + line + ", column " + column + ". Encountered: " + (eof ? " " : (StringParser.escapeString(String.valueOf(current), '"')) + " (" + (int) current + "), ") + "after : " + StringParser.escapeString(after, '"')); } /** Constructor with message and reason. */ public TokenMgrError(String message, int reason) { super(message); errorCode = reason; } /** Full Constructor. */ public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { eof = EOFSeen; state = lexState; line = errorLine; column = errorColumn; after = errorAfter; current = curChar; errorCode = reason; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/ReadonlyContext.java100644 0 0 3413 11673634324 25204 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * A readonly context wrapper. * @since 2.1 */ public final class ReadonlyContext implements JexlContext { /** The wrapped context. */ private final JexlContext wrapped; /** * Creates a new readonly context. * @param context the wrapped context */ public ReadonlyContext(JexlContext context) { wrapped = context; } /** {@inheritDoc} */ public Object get(String name) { return wrapped.get(name); } /** * Will throw an UnsupportedOperationException when called; the JexlEngine deals with it appropriately. * @param name the unused variable name * @param value the unused variable value */ public void set(String name, Object value) { throw new UnsupportedOperationException("Not supported."); } /** {@inheritDoc} */ public boolean has(String name) { return wrapped.has(name); } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/Script.java100644 0 0 7501 11673634322 23326 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; /** *

A JEXL Script.

*

A script is some valid JEXL syntax to be executed with * a given set of {@link JexlContext} variables.

*

A script is a group of statements, separated by semicolons.

*

The statements can be blocks (curly braces containing code), * Control statements such as if and while * as well as expressions and assignment statements.

* * @since 1.1 */ public interface Script { /** * Executes the script with the variables contained in the * supplied {@link JexlContext}. * * @param context A JexlContext containing variables. * @return The result of this script, usually the result of * the last statement. */ Object execute(JexlContext context); /** * Executes the script with the variables contained in the * supplied {@link JexlContext} and a set of arguments corresponding to the * parameters used during parsing. * * @param context A JexlContext containing variables. * @param args the arguments * @return The result of this script, usually the result of * the last statement. * @since 2.1 */ Object execute(JexlContext context, Object... args); /** * Returns the text of this Script. * @return The script to be executed. */ String getText(); /** * Gets this script parameters. * @return the parameters or null * @since 2.1 */ String[] getParameters(); /** * Gets this script local variables. * @return the local variables or null * @since 2.1 */ String[] getLocalVariables(); /** * Gets this script variables. *

Note that since variables can be in an ant-ish form (ie foo.bar.quux), each variable is returned as * a list of strings where each entry is a fragment of the variable ({"foo", "bar", "quux"} in the example.

* @return the variables or null * @since 2.1 */ Set> getVariables(); /** * Creates a Callable from this script. *

This allows to submit it to an executor pool and provides support for asynchronous calls.

*

The interpreter will handle interruption/cancellation gracefully if needed.

* @param context the context * @return the callable * @since 2.1 */ Callable callable(JexlContext context); /** * Creates a Callable from this script. *

This allows to submit it to an executor pool and provides support for asynchronous calls.

*

The interpreter will handle interruption/cancellation gracefully if needed.

* @param context the context * @param args the script arguments * @return the callable * @since 2.1 */ Callable callable(JexlContext context, Object... args); } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngine.java100644 0 0 32130 11673634324 27317 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.scripting; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import javax.script.AbstractScriptEngine; import javax.script.Bindings; import javax.script.Compilable; import javax.script.CompiledScript; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptException; import javax.script.SimpleBindings; import org.apache.commons.jexl2.JexlContext; import org.apache.commons.jexl2.JexlEngine; import org.apache.commons.jexl2.Script; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Implements the Jexl ScriptEngine for JSF-223. *

* This implementation gives access to both ENGINE_SCOPE and GLOBAL_SCOPE bindings. * When a JEXL script accesses a variable for read or write, * this implementation checks first ENGINE and then GLOBAL scope. * The first one found is used. * If no variable is found, and the JEXL script is writing to a variable, * it will be stored in the ENGINE scope. *

*

* The implementation also creates the "JEXL" script object as an instance of the * class {@link JexlScriptObject} for access to utility methods and variables. *

* See * Java Scripting API * Javadoc. * @since 2.0 */ public class JexlScriptEngine extends AbstractScriptEngine implements Compilable { /** The logger. */ private static final Log LOG = LogFactory.getLog(JexlScriptEngine.class); /** The shared expression cache size. */ private static final int CACHE_SIZE = 512; /** Reserved key for context (mandated by JSR-223). */ public static final String CONTEXT_KEY = "context"; /** Reserved key for JexlScriptObject. */ public static final String JEXL_OBJECT_KEY = "JEXL"; /** The JexlScriptObject instance. */ private final JexlScriptObject jexlObject; /** The factory which created this instance. */ private final ScriptEngineFactory parentFactory; /** The JEXL EL engine. */ private final JexlEngine jexlEngine; /** * Default constructor. *

* Only intended for use when not using a factory. * Sets the factory to {@link JexlScriptEngineFactory}. */ public JexlScriptEngine() { this(FactorySingletonHolder.DEFAULT_FACTORY); } /** * Implements engine and engine context properties for use by JEXL scripts. * Those properties are allways bound to the default engine scope context. *

* The following properties are defined: *

    *
  • in - refers to the engine scope reader that defaults to reading System.err
  • *
  • out - refers the engine scope writer that defaults to writing in System.out
  • *
  • err - refers to the engine scope writer that defaults to writing in System.err
  • *
  • logger - the JexlScriptEngine logger
  • *
  • System - the System.class
  • *
*

* @since 2.0 */ public class JexlScriptObject { /** * Gives access to the underlying JEXL engine shared between all ScriptEngine instances. *

Although this allows to manipulate various engine flags (lenient, debug, cache...) * for all JexlScriptEngine instances, you probably should only do so * if you are in strict control and sole user of the Jexl scripting feature.

* @return the shared underlying JEXL engine */ public JexlEngine getEngine() { return jexlEngine; } /** * Gives access to the engine scope output writer (defaults to System.out). * @return the engine output writer */ public PrintWriter getOut() { final Writer out = context.getWriter(); if (out instanceof PrintWriter) { return (PrintWriter) out; } else if (out != null) { return new PrintWriter(out, true); } else { return null; } } /** * Gives access to the engine scope error writer (defaults to System.err). * @return the engine error writer */ public PrintWriter getErr() { final Writer error = context.getErrorWriter(); if (error instanceof PrintWriter) { return (PrintWriter) error; } else if (error != null) { return new PrintWriter(error, true); } else { return null; } } /** * Gives access to the engine scope input reader (defaults to System.in). * @return the engine input reader */ public Reader getIn() { return context.getReader(); } /** * Gives access to System class. * @return System.class */ public Class getSystem() { return System.class; } /** * Gives access to the engine logger. * @return the JexlScriptEngine logger */ public Log getLogger() { return LOG; } } /** * Create a scripting engine using the supplied factory. * * @param factory the factory which created this instance. * @throws NullPointerException if factory is null */ public JexlScriptEngine(final ScriptEngineFactory factory) { if (factory == null) { throw new NullPointerException("ScriptEngineFactory must not be null"); } parentFactory = factory; jexlEngine = EngineSingletonHolder.DEFAULT_ENGINE; jexlObject = new JexlScriptObject(); } /** {@inheritDoc} */ public Bindings createBindings() { return new SimpleBindings(); } /** {@inheritDoc} */ public Object eval(final Reader reader, final ScriptContext context) throws ScriptException { // This is mandated by JSR-223 (see SCR.5.5.2 Methods) if (reader == null || context == null) { throw new NullPointerException("script and context must be non-null"); } return eval(readerToString(reader), context); } /** {@inheritDoc} */ public Object eval(final String script, final ScriptContext context) throws ScriptException { // This is mandated by JSR-223 (see SCR.5.5.2 Methods) if (script == null || context == null) { throw new NullPointerException("script and context must be non-null"); } // This is mandated by JSR-223 (end of section SCR.4.3.4.1.2 - Script Execution) context.setAttribute(CONTEXT_KEY, context, ScriptContext.ENGINE_SCOPE); try { Script jexlScript = jexlEngine.createScript(script); JexlContext ctxt = new JexlContextWrapper(context); return jexlScript.execute(ctxt); } catch (Exception e) { throw new ScriptException(e.toString()); } } /** {@inheritDoc} */ public ScriptEngineFactory getFactory() { return parentFactory; } /** {@inheritDoc} */ public CompiledScript compile(final String script) throws ScriptException { // This is mandated by JSR-223 if (script == null) { throw new NullPointerException("script must be non-null"); } try { Script jexlScript = jexlEngine.createScript(script); return new JexlCompiledScript(jexlScript); } catch (Exception e) { throw new ScriptException(e.toString()); } } /** {@inheritDoc} */ public CompiledScript compile(final Reader script) throws ScriptException { // This is mandated by JSR-223 if (script == null) { throw new NullPointerException("script must be non-null"); } return compile(readerToString(script)); } /** * Reads a script. * @param script the script reader * @return the script as a string * @throws ScriptException if an exception occurs during read */ private String readerToString(final Reader script) throws ScriptException { try { return JexlEngine.readerToString(script); } catch (IOException e) { throw new ScriptException(e); } } /** * Holds singleton JexlScriptEngineFactory (IODH). */ private static class FactorySingletonHolder { /** non instantiable. */ private FactorySingletonHolder() {} /** The engine factory singleton instance. */ private static final JexlScriptEngineFactory DEFAULT_FACTORY = new JexlScriptEngineFactory(); } /** * Holds singleton JexlScriptEngine (IODH). *

A single JEXL engine and Uberspect is shared by all instances of JexlScriptEngine.

*/ private static class EngineSingletonHolder { /** non instantiable. */ private EngineSingletonHolder() {} /** The JEXL engine singleton instance. */ private static final JexlEngine DEFAULT_ENGINE = new JexlEngine(null, null, null, LOG) { { this.setCache(CACHE_SIZE); } }; } /** * Wrapper to help convert a JSR-223 ScriptContext into a JexlContext. * * Current implementation only gives access to ENGINE_SCOPE binding. */ private final class JexlContextWrapper implements JexlContext { /** The wrapped script context. */ private final ScriptContext scriptContext; /** * Creates a context wrapper. * @param theContext the engine context. */ private JexlContextWrapper (final ScriptContext theContext){ scriptContext = theContext; } /** {@inheritDoc} */ public Object get(final String name) { final Object o = scriptContext.getAttribute(name); if (JEXL_OBJECT_KEY.equals(name)) { if (o != null) { LOG.warn("JEXL is a reserved variable name, user defined value is ignored"); } return jexlObject; } return o; } /** {@inheritDoc} */ public void set(final String name, final Object value) { int scope = scriptContext.getAttributesScope(name); if (scope == -1) { // not found, default to engine scope = ScriptContext.ENGINE_SCOPE; } scriptContext.getBindings(scope).put(name , value); } /** {@inheritDoc} */ public boolean has(final String name) { Bindings bnd = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE); return bnd.containsKey(name); } } /** * Wrapper to help convert a Jexl Script into a JSR-223 CompiledScript. */ private final class JexlCompiledScript extends CompiledScript { /** The underlying Jexl expression instance. */ private final Script script; /** * Creates an instance. * @param theScript to wrap */ private JexlCompiledScript(final Script theScript) { script = theScript; } /** {@inheritDoc} */ @Override public String toString() { return script.getText(); } /** {@inheritDoc} */ @Override public Object eval(final ScriptContext context) throws ScriptException { // This is mandated by JSR-223 (end of section SCR.4.3.4.1.2 - Script Execution) context.setAttribute(CONTEXT_KEY, context, ScriptContext.ENGINE_SCOPE); try { JexlContext ctxt = new JexlContextWrapper(context); return script.execute(ctxt); } catch (Exception e) { throw new ScriptException(e.toString()); } } /** {@inheritDoc} */ @Override public ScriptEngine getEngine() { return JexlScriptEngine.this; } } } ././@LongLink100644 0 0 145 11673650055 10263 Lustar 0 0 commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngineFactory.javacommons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/scripting/JexlScriptEngineFactory.java100644 0 0 11767 11673634324 30664 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.scripting; import java.util.Arrays; import java.util.Collections; import java.util.List; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import org.apache.commons.jexl2.JexlEngine; import org.apache.commons.jexl2.parser.StringParser; /** * Implements the Jexl ScriptEngineFactory for JSF-223. *

* Supports the following: * Language short names: "JEXL", "Jexl", "jexl", "JEXL2", "Jexl2", "jexl2"
* File Extensions: ".jexl", ".jexl2"
* "jexl2" etc. were added for engineVersion="2.0". *

*

* See * Java Scripting API * Javadoc. * @since 2.0 */ public class JexlScriptEngineFactory implements ScriptEngineFactory { /** {@inheritDoc} */ public String getEngineName() { return "JEXL Engine"; } /** {@inheritDoc} */ public String getEngineVersion() { return "2.0"; // ensure this is updated if function changes are made to this class } /** {@inheritDoc} */ public String getLanguageName() { return "JEXL"; } /** {@inheritDoc} */ public String getLanguageVersion() { return "2.0"; // TODO this should be derived from the actual version } /** {@inheritDoc} */ public String getMethodCallSyntax(String obj, String m, String[] args) { StringBuilder sb = new StringBuilder(); sb.append(obj); sb.append('.'); sb.append(m); sb.append('('); boolean needComma = false; for(String arg : args){ if (needComma) { sb.append(','); } sb.append(arg); needComma = true; } sb.append(')'); return sb.toString(); } /** {@inheritDoc} */ public List getExtensions() { return Collections.unmodifiableList(Arrays.asList("jexl", "jexl2")); } /** {@inheritDoc} */ public List getMimeTypes() { return Collections.unmodifiableList(Arrays.asList("application/x-jexl", "application/x-jexl2")); } /** {@inheritDoc} */ public List getNames() { return Collections.unmodifiableList(Arrays.asList("JEXL", "Jexl", "jexl", "JEXL2", "Jexl2", "jexl2")); } /** {@inheritDoc} */ public String getOutputStatement(String toDisplay) { if (toDisplay == null) { return "JEXL.out.print(null)"; } else { return "JEXL.out.print("+StringParser.escapeString(toDisplay, '\'')+")"; } } /** {@inheritDoc} */ public Object getParameter(String key) { if (key.equals(ScriptEngine.ENGINE)) { return getEngineName(); } else if (key.equals(ScriptEngine.ENGINE_VERSION)) { return getEngineVersion(); } else if (key.equals(ScriptEngine.NAME)) { return getNames(); } else if (key.equals(ScriptEngine.LANGUAGE)) { return getLanguageName(); } else if(key.equals(ScriptEngine.LANGUAGE_VERSION)) { return getLanguageVersion(); } else if (key.equals("THREADING")) { /* * To implement multithreading, the scripting engine context (inherited from AbstractScriptEngine) * would need to be made thread-safe; so would the setContext/getContext methods. * It is easier to share the underlying Uberspect and JEXL engine instance, especially * with an expression cache. */ return null; } return null; } /** {@inheritDoc} */ public String getProgram(String[] statements) { StringBuilder sb = new StringBuilder(); for(String statement : statements){ sb.append(JexlEngine.cleanExpression(statement)); if (!statement.endsWith(";")){ sb.append(';'); } } return sb.toString(); } /** {@inheritDoc} */ public ScriptEngine getScriptEngine() { JexlScriptEngine engine = new JexlScriptEngine(this); return engine; } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/scripting/Main.java100644 0 0 5252 11673634324 24753 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.scripting; import java.io.BufferedReader; import java.io.FileReader; import java.io.InputStreamReader; import javax.script.ScriptEngine; import javax.script.ScriptException; /** * Test application for JexlScriptEngine (JSR-223 implementation). * @since 2.0 */ public class Main { /** * Test application for JexlScriptEngine (JSR-223 implementation). * * If a single argument is present, it is treated as a filename of a JEXL * script to be evaluated. Any exceptions terminate the application. * * Otherwise, lines are read from standard input and evaluated. * ScriptExceptions are logged, and do not cause the application to exit. * This is done so that interactive testing is easier. * * @param args (optional) filename to evaluate. Stored in the args variable. * * @throws Exception if parsing or IO fail */ public static void main(String[] args) throws Exception { JexlScriptEngineFactory fac = new JexlScriptEngineFactory(); ScriptEngine engine = fac.getScriptEngine(); engine.put("args", args); if (args.length == 1){ Object value = engine.eval(new FileReader(args[0])); System.out.println("Return value: "+value); } else { BufferedReader console = new BufferedReader(new InputStreamReader(System.in)); String line; System.out.print("> "); while(null != (line=console.readLine())){ try { Object value = engine.eval(line); System.out.println("Return value: "+value); } catch (ScriptException e) { System.out.println(e.getLocalizedMessage()); } System.out.print("> "); } } } } commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/scripting/package.html100644 0 0 2532 11673634324 25503 0ustar 0 0 Package Documentation for org.apache.commons.jexl2.scripting Package

Contains the JSR-223 Scripting Engine for JEXL script.

This internal package is not intended for public usage and there is no guarantee that its public classes or methods will remain as is in subsequent versions.

commons-jexl-2.1.1-src/src/main/java/org/apache/commons/jexl2/UnifiedJEXL.java100644 0 0 156134 11673634322 24177 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.apache.commons.jexl2.introspection.JexlMethod; import org.apache.commons.jexl2.introspection.Uberspect; import org.apache.commons.jexl2.parser.ASTJexlScript; import org.apache.commons.jexl2.parser.JexlNode; import org.apache.commons.jexl2.parser.StringParser; /** * An evaluator similar to the Unified EL evaluator used in JSP/JSF based on JEXL. * It is intended to be used in configuration modules, XML based frameworks or JSP taglibs * and facilitate the implementation of expression evaluation. *

* An expression can mix immediate, deferred and nested sub-expressions as well as string constants; *

    *
  • The "immediate" syntax is of the form "...${jexl-expr}..."
  • *
  • The "deferred" syntax is of the form "...#{jexl-expr}..."
  • *
  • The "nested" syntax is of the form "...#{...${jexl-expr0}...}..."
  • *
  • The "composite" syntax is of the form "...${jexl-expr0}... #{jexl-expr1}..."
  • *
*

*

* Deferred & immediate expression carry different intentions: *

    *
  • An immediate expression indicate that evaluation is intended to be performed close to * the definition/parsing point.
  • *
  • A deferred expression indicate that evaluation is intended to occur at a later stage.
  • *
*

*

* For instance: "Hello ${name}, now is #{time}" is a composite "deferred" expression since one * of its subexpressions is deferred. Furthermore, this (composite) expression intent is * to perform two evaluations; one close to its definition and another one in a later * phase. *

*

* The API reflects this feature in 2 methods, prepare and evaluate. The prepare method * will evaluate the immediate subexpression and return an expression that contains only * the deferred subexpressions (& constants), a prepared expression. Such a prepared expression * is suitable for a later phase evaluation that may occur with a different JexlContext. * Note that it is valid to call evaluate without prepare in which case the same JexlContext * is used for the 2 evaluation phases. *

*

* In the most common use-case where deferred expressions are to be kept around as properties of objects, * one should parse & prepare an expression before storing it and evaluate it each time * the property storing it is accessed. *

*

* Note that nested expression use the JEXL syntax as in: * "#{${bar}+'.charAt(2)'}" * The most common mistake leading to an invalid expression being the following: * "#{${bar}charAt(2)}" *

*

Also note that methods that parse evaluate expressions may throw unchecked exceptions; * The {@link UnifiedJEXL.Exception} are thrown when the engine instance is in "non-silent" mode * but since these are RuntimeException, user-code should catch them where appropriate. *

* @since 2.0 */ public final class UnifiedJEXL { /** The JEXL engine instance. */ private final JexlEngine jexl; /** The expression cache. */ private final JexlEngine.SoftCache cache; /** The default cache size. */ private static final int CACHE_SIZE = 256; /** The first character for immediate expressions. */ private static final char IMM_CHAR = '$'; /** The first character for deferred expressions. */ private static final char DEF_CHAR = '#'; /** * Creates a new instance of UnifiedJEXL with a default size cache. * @param aJexl the JexlEngine to use. */ public UnifiedJEXL(JexlEngine aJexl) { this(aJexl, CACHE_SIZE); } /** * Creates a new instance of UnifiedJEXL creating a local cache. * @param aJexl the JexlEngine to use. * @param cacheSize the number of expressions in this cache */ public UnifiedJEXL(JexlEngine aJexl, int cacheSize) { this.jexl = aJexl; this.cache = aJexl.new SoftCache(cacheSize); } /** * Types of expressions. * Each instance carries a counter index per (composite sub-) expression type. * @see ExpressionBuilder */ private static enum ExpressionType { /** Constant expression, count index 0. */ CONSTANT(0), /** Immediate expression, count index 1. */ IMMEDIATE(1), /** Deferred expression, count index 2. */ DEFERRED(2), /** Nested (which are deferred) expressions, count index 2. */ NESTED(2), /** Composite expressions are not counted, index -1. */ COMPOSITE(-1); /** The index in arrays of expression counters for composite expressions. */ private final int index; /** * Creates an ExpressionType. * @param idx the index for this type in counters arrays. */ ExpressionType(int idx) { this.index = idx; } } /** * A helper class to build expressions. * Keeps count of sub-expressions by type. */ private static class ExpressionBuilder { /** Per expression type counters. */ private final int[] counts; /** The list of expressions. */ private final ArrayList expressions; /** * Creates a builder. * @param size the initial expression array size */ ExpressionBuilder(int size) { counts = new int[]{0, 0, 0}; expressions = new ArrayList(size <= 0 ? 3 : size); } /** * Adds an expression to the list of expressions, maintain per-type counts. * @param expr the expression to add */ void add(Expression expr) { counts[expr.getType().index] += 1; expressions.add(expr); } /** * Builds an expression from a source, performs checks. * @param el the unified el instance * @param source the source expression * @return an expression */ Expression build(UnifiedJEXL el, Expression source) { int sum = 0; for (int count : counts) { sum += count; } if (expressions.size() != sum) { StringBuilder error = new StringBuilder("parsing algorithm error, exprs: "); error.append(expressions.size()); error.append(", constant:"); error.append(counts[ExpressionType.CONSTANT.index]); error.append(", immediate:"); error.append(counts[ExpressionType.IMMEDIATE.index]); error.append(", deferred:"); error.append(counts[ExpressionType.DEFERRED.index]); throw new IllegalStateException(error.toString()); } // if only one sub-expr, no need to create a composite if (expressions.size() == 1) { return expressions.get(0); } else { return el.new CompositeExpression(counts, expressions, source); } } } /** * Gets the JexlEngine underlying the UnifiedJEXL. * @return the JexlEngine */ public JexlEngine getEngine() { return jexl; } /** * Clears the cache. * @since 2.1 */ public void clearCache() { synchronized (cache) { cache.clear(); } } /** * The sole type of (runtime) exception the UnifiedJEXL can throw. */ public static class Exception extends RuntimeException { /** Serial version UID. */ private static final long serialVersionUID = -8201402995815975726L; /** * Creates a UnifiedJEXL.Exception. * @param msg the exception message * @param cause the exception cause */ public Exception(String msg, Throwable cause) { super(msg, cause); } } /** * The abstract base class for all expressions, immediate '${...}' and deferred '#{...}'. */ public abstract class Expression { /** The source of this expression (see {@link UnifiedJEXL.Expression#prepare}). */ protected final Expression source; /** * Creates an expression. * @param src the source expression if any */ Expression(Expression src) { this.source = src != null ? src : this; } /** * Checks whether this expression is immediate. * @return true if immediate, false otherwise */ public boolean isImmediate() { return true; } /** * Checks whether this expression is deferred. * @return true if deferred, false otherwise */ public final boolean isDeferred() { return !isImmediate(); } /** * Gets this expression type. * @return its type */ abstract ExpressionType getType(); /** * Formats this expression, adding its source string representation in * comments if available: 'expression /*= source *\/'' . * Note: do not override; will be made final in a future release. * @return the formatted expression string */ @Override public String toString() { StringBuilder strb = new StringBuilder(); asString(strb); if (source != this) { strb.append(" /*= "); strb.append(source.toString()); strb.append(" */"); } return strb.toString(); } /** * Generates this expression's string representation. * @return the string representation */ public String asString() { StringBuilder strb = new StringBuilder(); asString(strb); return strb.toString(); } /** * Adds this expression's string representation to a StringBuilder. * @param strb the builder to fill * @return the builder argument */ public abstract StringBuilder asString(StringBuilder strb); /** * Gets the list of variables accessed by this expression. *

This method will visit all nodes of the sub-expressions and extract all variables whether they * are written in 'dot' or 'bracketed' notation. (a.b is equivalent to a['b']).

* @return the set of variables, each as a list of strings (ant-ish variables use more than 1 string) * or the empty set if no variables are used * @since 2.1 */ public Set> getVariables() { return Collections.emptySet(); } /** * Fills up the list of variables accessed by this expression. * @param refs the set of variable being filled * @since 2.1 */ protected void getVariables(Set> refs) { // nothing to do } /** * Evaluates the immediate sub-expressions. *

* When the expression is dependant upon immediate and deferred sub-expressions, * evaluates the immediate sub-expressions with the context passed as parameter * and returns this expression deferred form. *

*

* In effect, this binds the result of the immediate sub-expressions evaluation in the * context, allowing to differ evaluation of the remaining (deferred) expression within another context. * This only has an effect to nested & composite expressions that contain differed & immediate sub-expressions. *

*

* If the underlying JEXL engine is silent, errors will be logged through its logger as warning. *

* Note: do not override; will be made final in a future release. * @param context the context to use for immediate expression evaluations * @return an expression or null if an error occurs and the {@link JexlEngine} is running in silent mode * @throws UnifiedJEXL.Exception if an error occurs and the {@link JexlEngine} is not in silent mode */ public Expression prepare(JexlContext context) { try { Interpreter interpreter = new Interpreter(jexl, context, !jexl.isLenient(), jexl.isSilent()); if (context instanceof TemplateContext) { interpreter.setFrame(((TemplateContext) context).getFrame()); } return prepare(interpreter); } catch (JexlException xjexl) { Exception xuel = createException("prepare", this, xjexl); if (jexl.isSilent()) { jexl.logger.warn(xuel.getMessage(), xuel.getCause()); return null; } throw xuel; } } /** * Evaluates this expression. *

* If the underlying JEXL engine is silent, errors will be logged through its logger as warning. *

* Note: do not override; will be made final in a future release. * @param context the variable context * @return the result of this expression evaluation or null if an error occurs and the {@link JexlEngine} is * running in silent mode * @throws UnifiedJEXL.Exception if an error occurs and the {@link JexlEngine} is not silent */ public Object evaluate(JexlContext context) { try { Interpreter interpreter = new Interpreter(jexl, context, !jexl.isLenient(), jexl.isSilent()); if (context instanceof TemplateContext) { interpreter.setFrame(((TemplateContext) context).getFrame()); } return evaluate(interpreter); } catch (JexlException xjexl) { Exception xuel = createException("prepare", this, xjexl); if (jexl.isSilent()) { jexl.logger.warn(xuel.getMessage(), xuel.getCause()); return null; } throw xuel; } } /** * Retrieves this expression's source expression. * If this expression was prepared, this allows to retrieve the * original expression that lead to it. * Other expressions return themselves. * @return the source expression */ public final Expression getSource() { return source; } /** * Prepares a sub-expression for interpretation. * @param interpreter a JEXL interpreter * @return a prepared expression * @throws JexlException (only for nested & composite) */ protected Expression prepare(Interpreter interpreter) { return this; } /** * Intreprets a sub-expression. * @param interpreter a JEXL interpreter * @return the result of interpretation * @throws JexlException (only for nested & composite) */ protected abstract Object evaluate(Interpreter interpreter); } /** A constant expression. */ private class ConstantExpression extends Expression { /** The constant held by this expression. */ private final Object value; /** * Creates a constant expression. *

* If the wrapped constant is a string, it is treated * as a JEXL strings with respect to escaping. *

* @param val the constant value * @param source the source expression if any */ ConstantExpression(Object val, Expression source) { super(source); if (val == null) { throw new NullPointerException("constant can not be null"); } if (val instanceof String) { val = StringParser.buildString((String) val, false); } this.value = val; } /** {@inheritDoc} */ @Override ExpressionType getType() { return ExpressionType.CONSTANT; } /** {@inheritDoc} */ @Override public StringBuilder asString(StringBuilder strb) { if (value != null) { strb.append(value.toString()); } return strb; } /** {@inheritDoc} */ @Override protected Object evaluate(Interpreter interpreter) { return value; } } /** The base for Jexl based expressions. */ private abstract class JexlBasedExpression extends Expression { /** The JEXL string for this expression. */ protected final CharSequence expr; /** The JEXL node for this expression. */ protected final JexlNode node; /** * Creates a JEXL interpretable expression. * @param theExpr the expression as a string * @param theNode the expression as an AST * @param theSource the source expression if any */ protected JexlBasedExpression(CharSequence theExpr, JexlNode theNode, Expression theSource) { super(theSource); this.expr = theExpr; this.node = theNode; } /** {@inheritDoc} */ @Override public StringBuilder asString(StringBuilder strb) { strb.append(isImmediate() ? IMM_CHAR : DEF_CHAR); strb.append("{"); strb.append(expr); strb.append("}"); return strb; } /** {@inheritDoc} */ @Override protected Object evaluate(Interpreter interpreter) { return interpreter.interpret(node); } /** {@inheritDoc} */ @Override public Set> getVariables() { Set> refs = new LinkedHashSet>(); getVariables(refs); return refs; } /** {@inheritDoc} */ @Override protected void getVariables(Set> refs) { jexl.getVariables(node, refs, null); } } /** An immediate expression: ${jexl}. */ private class ImmediateExpression extends JexlBasedExpression { /** * Creates an immediate expression. * @param expr the expression as a string * @param node the expression as an AST * @param source the source expression if any */ ImmediateExpression(CharSequence expr, JexlNode node, Expression source) { super(expr, node, source); } /** {@inheritDoc} */ @Override ExpressionType getType() { return ExpressionType.IMMEDIATE; } /** {@inheritDoc} */ @Override protected Expression prepare(Interpreter interpreter) { // evaluate immediate as constant Object value = evaluate(interpreter); return value != null ? new ConstantExpression(value, source) : null; } } /** A deferred expression: #{jexl}. */ private class DeferredExpression extends JexlBasedExpression { /** * Creates a deferred expression. * @param expr the expression as a string * @param node the expression as an AST * @param source the source expression if any */ DeferredExpression(CharSequence expr, JexlNode node, Expression source) { super(expr, node, source); } /** {@inheritDoc} */ @Override public boolean isImmediate() { return false; } /** {@inheritDoc} */ @Override ExpressionType getType() { return ExpressionType.DEFERRED; } /** {@inheritDoc} */ @Override protected Expression prepare(Interpreter interpreter) { return new ImmediateExpression(expr, node, source); } /** {@inheritDoc} */ @Override protected void getVariables(Set> refs) { // noop } } /** * An immediate expression nested into a deferred expression. * #{...${jexl}...} * Note that the deferred syntax is JEXL's, not UnifiedJEXL. */ private class NestedExpression extends JexlBasedExpression { /** * Creates a nested expression. * @param expr the expression as a string * @param node the expression as an AST * @param source the source expression if any */ NestedExpression(CharSequence expr, JexlNode node, Expression source) { super(expr, node, source); if (this.source != this) { throw new IllegalArgumentException("Nested expression can not have a source"); } } @Override public StringBuilder asString(StringBuilder strb) { strb.append(expr); return strb; } /** {@inheritDoc} */ @Override public boolean isImmediate() { return false; } /** {@inheritDoc} */ @Override ExpressionType getType() { return ExpressionType.NESTED; } /** {@inheritDoc} */ @Override protected Expression prepare(Interpreter interpreter) { String value = interpreter.interpret(node).toString(); JexlNode dnode = jexl.parse(value, jexl.isDebug() ? node.debugInfo() : null, null); return new ImmediateExpression(value, dnode, this); } /** {@inheritDoc} */ @Override protected Object evaluate(Interpreter interpreter) { return prepare(interpreter).evaluate(interpreter); } } /** A composite expression: "... ${...} ... #{...} ...". */ private class CompositeExpression extends Expression { /** Bit encoded (deferred count > 0) bit 1, (immediate count > 0) bit 0. */ private final int meta; /** The list of sub-expression resulting from parsing. */ protected final Expression[] exprs; /** * Creates a composite expression. * @param counters counters of expression per type * @param list the sub-expressions * @param src the source for this expresion if any */ CompositeExpression(int[] counters, ArrayList list, Expression src) { super(src); this.exprs = list.toArray(new Expression[list.size()]); this.meta = (counters[ExpressionType.DEFERRED.index] > 0 ? 2 : 0) | (counters[ExpressionType.IMMEDIATE.index] > 0 ? 1 : 0); } /** {@inheritDoc} */ @Override public boolean isImmediate() { // immediate if no deferred return (meta & 2) == 0; } /** {@inheritDoc} */ @Override ExpressionType getType() { return ExpressionType.COMPOSITE; } /** {@inheritDoc} */ @Override public StringBuilder asString(StringBuilder strb) { for (Expression e : exprs) { e.asString(strb); } return strb; } /** {@inheritDoc} */ @Override public Set> getVariables() { Set> refs = new LinkedHashSet>(); for (Expression expr : exprs) { expr.getVariables(refs); } return refs; } /** {@inheritDoc} */ @Override protected Expression prepare(Interpreter interpreter) { // if this composite is not its own source, it is already prepared if (source != this) { return this; } // we need to prepare all sub-expressions final int size = exprs.length; final ExpressionBuilder builder = new ExpressionBuilder(size); // tracking whether prepare will return a different expression boolean eq = true; for (int e = 0; e < size; ++e) { Expression expr = exprs[e]; Expression prepared = expr.prepare(interpreter); // add it if not null if (prepared != null) { builder.add(prepared); } // keep track of expression equivalence eq &= expr == prepared; } Expression ready = eq ? this : builder.build(UnifiedJEXL.this, this); return ready; } /** {@inheritDoc} */ @Override protected Object evaluate(Interpreter interpreter) { final int size = exprs.length; Object value = null; // common case: evaluate all expressions & concatenate them as a string StringBuilder strb = new StringBuilder(); for (int e = 0; e < size; ++e) { value = exprs[e].evaluate(interpreter); if (value != null) { strb.append(value.toString()); } } value = strb.toString(); return value; } } /** Creates a a {@link UnifiedJEXL.Expression} from an expression string. * Uses & fills up the expression cache if any. *

* If the underlying JEXL engine is silent, errors will be logged through its logger as warnings. *

* @param expression the UnifiedJEXL string expression * @return the UnifiedJEXL object expression, null if silent and an error occured * @throws UnifiedJEXL.Exception if an error occurs and the {@link JexlEngine} is not silent */ public Expression parse(String expression) { Exception xuel = null; Expression stmt = null; try { if (cache == null) { stmt = parseExpression(expression, null); } else { synchronized (cache) { stmt = cache.get(expression); if (stmt == null) { stmt = parseExpression(expression, null); cache.put(expression, stmt); } } } } catch (JexlException xjexl) { xuel = new Exception("failed to parse '" + expression + "'", xjexl); } catch (Exception xany) { xuel = xany; } finally { if (xuel != null) { if (jexl.isSilent()) { jexl.logger.warn(xuel.getMessage(), xuel.getCause()); return null; } throw xuel; } } return stmt; } /** * Creates a UnifiedJEXL.Exception from a JexlException. * @param action parse, prepare, evaluate * @param expr the expression * @param xany the exception * @return an exception containing an explicit error message */ private Exception createException(String action, Expression expr, java.lang.Exception xany) { StringBuilder strb = new StringBuilder("failed to "); strb.append(action); if (expr != null) { strb.append(" '"); strb.append(expr.toString()); strb.append("'"); } Throwable cause = xany.getCause(); if (cause != null) { String causeMsg = cause.getMessage(); if (causeMsg != null) { strb.append(", "); strb.append(causeMsg); } } return new Exception(strb.toString(), xany); } /** The different parsing states. */ private static enum ParseState { /** Parsing a constant. */ CONST, /** Parsing after $ .*/ IMMEDIATE0, /** Parsing after # .*/ DEFERRED0, /** Parsing after ${ .*/ IMMEDIATE1, /** Parsing after #{ .*/ DEFERRED1, /** Parsing after \ .*/ ESCAPE } /** * Parses a unified expression. * @param expr the string expression * @param scope the expression scope * @return the expression instance * @throws JexlException if an error occur during parsing */ private Expression parseExpression(String expr, JexlEngine.Scope scope) { final int size = expr.length(); ExpressionBuilder builder = new ExpressionBuilder(0); StringBuilder strb = new StringBuilder(size); ParseState state = ParseState.CONST; int inner = 0; boolean nested = false; int inested = -1; for (int i = 0; i < size; ++i) { char c = expr.charAt(i); switch (state) { default: // in case we ever add new expression type throw new UnsupportedOperationException("unexpected expression type"); case CONST: if (c == IMM_CHAR) { state = ParseState.IMMEDIATE0; } else if (c == DEF_CHAR) { inested = i; state = ParseState.DEFERRED0; } else if (c == '\\') { state = ParseState.ESCAPE; } else { // do buildup expr strb.append(c); } break; case IMMEDIATE0: // $ if (c == '{') { state = ParseState.IMMEDIATE1; // if chars in buffer, create constant if (strb.length() > 0) { Expression cexpr = new ConstantExpression(strb.toString(), null); builder.add(cexpr); strb.delete(0, Integer.MAX_VALUE); } } else { // revert to CONST strb.append(IMM_CHAR); strb.append(c); state = ParseState.CONST; } break; case DEFERRED0: // # if (c == '{') { state = ParseState.DEFERRED1; // if chars in buffer, create constant if (strb.length() > 0) { Expression cexpr = new ConstantExpression(strb.toString(), null); builder.add(cexpr); strb.delete(0, Integer.MAX_VALUE); } } else { // revert to CONST strb.append(DEF_CHAR); strb.append(c); state = ParseState.CONST; } break; case IMMEDIATE1: // ${... if (c == '}') { // materialize the immediate expr Expression iexpr = new ImmediateExpression( strb.toString(), jexl.parse(strb, null, scope), null); builder.add(iexpr); strb.delete(0, Integer.MAX_VALUE); state = ParseState.CONST; } else { // do buildup expr strb.append(c); } break; case DEFERRED1: // #{... // skip inner strings (for '}') if (c == '"' || c == '\'') { strb.append(c); i = StringParser.readString(strb, expr, i + 1, c); continue; } // nested immediate in deferred; need to balance count of '{' & '}' if (c == '{') { if (expr.charAt(i - 1) == IMM_CHAR) { inner += 1; strb.deleteCharAt(strb.length() - 1); nested = true; } continue; } // closing '}' if (c == '}') { // balance nested immediate if (inner > 0) { inner -= 1; } else { // materialize the nested/deferred expr Expression dexpr = null; if (nested) { dexpr = new NestedExpression( expr.substring(inested, i + 1), jexl.parse(strb, null, scope), null); } else { dexpr = new DeferredExpression( strb.toString(), jexl.parse(strb, null, scope), null); } builder.add(dexpr); strb.delete(0, Integer.MAX_VALUE); nested = false; state = ParseState.CONST; } } else { // do buildup expr strb.append(c); } break; case ESCAPE: if (c == DEF_CHAR) { strb.append(DEF_CHAR); } else if (c == IMM_CHAR) { strb.append(IMM_CHAR); } else { strb.append('\\'); strb.append(c); } state = ParseState.CONST; } } // we should be in that state if (state != ParseState.CONST) { throw new Exception("malformed expression: " + expr, null); } // if any chars were buffered, add them as a constant if (strb.length() > 0) { Expression cexpr = new ConstantExpression(strb.toString(), null); builder.add(cexpr); } return builder.build(this, null); } /** * The enum capturing the difference between verbatim and code source fragments. */ private static enum BlockType { /** Block is to be output "as is". */ VERBATIM, /** Block is a directive, ie a fragment of code. */ DIRECTIVE; } /** * Abstract the source fragments, verbatim or immediate typed text blocks. * @since 2.1 */ private static final class TemplateBlock { /** The type of block, verbatim or directive. */ private final BlockType type; /** The actual contexnt. */ private final String body; /** * Creates a new block. * @param theType the type * @param theBlock the content */ TemplateBlock(BlockType theType, String theBlock) { type = theType; body = theBlock; } @Override public String toString() { return body; } } /** * A Template is a script that evaluates by writing its content through a Writer. * This is a simplified replacement for Velocity that uses JEXL (instead of OGNL/VTL) as the scripting * language. *

* The source text is parsed considering each line beginning with '$$' (as default pattern) as JEXL script code * and all others as Unified JEXL expressions; those expressions will be invoked from the script during * evaluation and their output gathered through a writer. * It is thus possible to use looping or conditional construct "around" expressions generating output. *

* For instance: *

     * $$ for(var x : [1, 3, 5, 42, 169]) {
     * $$   if (x == 42) {
     * Life, the universe, and everything
     * $$   } else if (x > 42) {
     * The value $(x} is over fourty-two
     * $$   } else {
     * The value ${x} is under fourty-two
     * $$   }
     * $$ }
     * 
* Will evaluate as: *

     * The value 1 is under fourty-two
     * The value 3 is under fourty-two
     * The value 5 is under fourty-two
     * Life, the universe, and everything
     * The value 169 is over fourty-two
     * 
*

* During evaluation, the template context exposes its writer as '$jexl' which is safe to use in this case. * This allows writing directly through the writer without adding new-lines as in: *

     * $$ for(var cell : cells) { $jexl.print(cell); $jexl.print(';') }
     * 
*

*

* A template is expanded as one JEXL script and a list of UnifiedJEXL expressions; each UnifiedJEXL expression * being replace in the script by a call to jexl:print(expr) (the expr is in fact the expr number in the template). * This integration uses a specialized JexlContext (TemplateContext) that serves as a namespace (for jexl:) * and stores the expression array and the writer (java.io.Writer) that the 'jexl:print(...)' * delegates the output generation to. *

* @since 2.1 */ public final class Template { /** The prefix marker. */ private final String prefix; /** The array of source blocks. */ private final TemplateBlock[] source; /** The resulting script. */ private final ASTJexlScript script; /** The UnifiedJEXL expressions called by the script. */ private final Expression[] exprs; /** * Creates a new template from an input. * @param directive the prefix for lines of code; can not be "$", "${", "#" or "#{" * since this would preclude being able to differentiate directives and UnifiedJEXL expressions * @param reader the input reader * @param parms the parameter names * @throws NullPointerException if either the directive prefix or input is null * @throws IllegalArgumentException if the directive prefix is invalid */ public Template(String directive, Reader reader, String... parms) { if (directive == null) { throw new NullPointerException("null prefix"); } if ("$".equals(directive) || "${".equals(directive) || "#".equals(directive) || "#{".equals(directive)) { throw new IllegalArgumentException(directive + ": is not a valid directive pattern"); } if (reader == null) { throw new NullPointerException("null input"); } JexlEngine.Scope scope = new JexlEngine.Scope(parms); prefix = directive; List blocks = readTemplate(prefix, reader); List uexprs = new ArrayList(); StringBuilder strb = new StringBuilder(); int nuexpr = 0; int codeStart = -1; for (int b = 0; b < blocks.size(); ++b) { TemplateBlock block = blocks.get(b); if (block.type == BlockType.VERBATIM) { strb.append("jexl:print("); strb.append(nuexpr++); strb.append(");"); } else { // keep track of first block of code, the frame creator if (codeStart < 0) { codeStart = b; } strb.append(block.body); } } // parse the script script = getEngine().parse(strb.toString(), null, scope); scope = script.getScope(); // parse the exprs using the code frame for those appearing after the first block of code for (int b = 0; b < blocks.size(); ++b) { TemplateBlock block = blocks.get(b); if (block.type == BlockType.VERBATIM) { uexprs.add(UnifiedJEXL.this.parseExpression(block.body, b > codeStart ? scope : null)); } } source = blocks.toArray(new TemplateBlock[blocks.size()]); exprs = uexprs.toArray(new Expression[uexprs.size()]); } /** * Private ctor used to expand deferred expressions during prepare. * @param thePrefix the directive prefix * @param theSource the source * @param theScript the script * @param theExprs the expressions */ private Template(String thePrefix, TemplateBlock[] theSource, ASTJexlScript theScript, Expression[] theExprs) { prefix = thePrefix; source = theSource; script = theScript; exprs = theExprs; } @Override public String toString() { StringBuilder strb = new StringBuilder(); for (TemplateBlock block : source) { if (block.type == BlockType.DIRECTIVE) { strb.append(prefix); } strb.append(block.toString()); strb.append('\n'); } return strb.toString(); } /** * Recreate the template source from its inner components. * @return the template source rewritten */ public String asString() { StringBuilder strb = new StringBuilder(); int e = 0; for (int b = 0; b < source.length; ++b) { TemplateBlock block = source[b]; if (block.type == BlockType.DIRECTIVE) { strb.append(prefix); } else { exprs[e++].asString(strb); } } return strb.toString(); } /** * Prepares this template by expanding any contained deferred expression. * @param context the context to prepare against * @return the prepared version of the template */ public Template prepare(JexlContext context) { JexlEngine.Frame frame = script.createFrame((Object[]) null); TemplateContext tcontext = new TemplateContext(context, frame, exprs, null); Expression[] immediates = new Expression[exprs.length]; for (int e = 0; e < exprs.length; ++e) { immediates[e] = exprs[e].prepare(tcontext); } return new Template(prefix, source, script, immediates); } /** * Evaluates this template. * @param context the context to use during evaluation * @param writer the writer to use for output */ public void evaluate(JexlContext context, Writer writer) { evaluate(context, writer, (Object[]) null); } /** * Evaluates this template. * @param context the context to use during evaluation * @param writer the writer to use for output * @param args the arguments */ public void evaluate(JexlContext context, Writer writer, Object... args) { JexlEngine.Frame frame = script.createFrame(args); TemplateContext tcontext = new TemplateContext(context, frame, exprs, writer); Interpreter interpreter = jexl.createInterpreter(tcontext, !jexl.isLenient(), false); interpreter.setFrame(frame); interpreter.interpret(script); } } /** * The type of context to use during evaluation of templates. *

This context exposes its writer as '$jexl' to the scripts.

*

public for introspection purpose.

* @since 2.1 */ public final class TemplateContext implements JexlContext, NamespaceResolver { /** The wrapped context. */ private final JexlContext wrap; /** The array of UnifiedJEXL expressions. */ private final Expression[] exprs; /** The writer used to output. */ private final Writer writer; /** The call frame. */ private final JexlEngine.Frame frame; /** * Creates a template context instance. * @param jcontext the base context * @param jframe the calling frame * @param expressions the list of expression from the template to evaluate * @param out the output writer */ protected TemplateContext(JexlContext jcontext, JexlEngine.Frame jframe, Expression[] expressions, Writer out) { wrap = jcontext; frame = jframe; exprs = expressions; writer = out; } /** * Gets this context calling frame. * @return the engine frame */ public JexlEngine.Frame getFrame() { return frame; } /** {@inheritDoc} */ public Object get(String name) { if ("$jexl".equals(name)) { return writer; } else { return wrap.get(name); } } /** {@inheritDoc} */ public void set(String name, Object value) { wrap.set(name, value); } /** {@inheritDoc} */ public boolean has(String name) { return wrap.has(name); } /** {@inheritDoc} */ public Object resolveNamespace(String ns) { if ("jexl".equals(ns)) { return this; } else if (wrap instanceof NamespaceResolver) { return ((NamespaceResolver) wrap).resolveNamespace(ns); } else { return null; } } /** * Includes a call to another template. *

Evaluates a template using this template initial context and writer.

* @param template the template to evaluate * @param args the arguments */ public void include(Template template, Object... args) { template.evaluate(wrap, writer, args); } /** * Prints an expression result. * @param e the expression number */ public void print(int e) { if (e < 0 || e >= exprs.length) { return; } Expression expr = exprs[e]; if (expr.isDeferred()) { expr = expr.prepare(wrap); } if (expr instanceof CompositeExpression) { printComposite((CompositeExpression) expr); } else { doPrint(expr.evaluate(this)); } } /** * Prints a composite expression. * @param composite the composite expression */ protected void printComposite(CompositeExpression composite) { Expression[] cexprs = composite.exprs; final int size = cexprs.length; Object value = null; for (int e = 0; e < size; ++e) { value = cexprs[e].evaluate(this); doPrint(value); } } /** * Prints to output. *

This will dynamically try to find the best suitable method in the writer through uberspection. * Subclassing Writer by adding 'print' methods should be the preferred way to specialize output. *

* @param arg the argument to print out */ private void doPrint(Object arg) { try { if (arg instanceof CharSequence) { writer.write(arg.toString()); } else if (arg != null) { Object[] value = {arg}; Uberspect uber = getEngine().getUberspect(); JexlMethod method = uber.getMethod(writer, "print", value, null); if (method != null) { method.invoke(writer, value); } else { writer.write(arg.toString()); } } } catch (java.io.IOException xio) { throw createException("call print", null, xio); } catch (java.lang.Exception xany) { throw createException("invoke print", null, xany); } } } /** * Whether a sequence starts with a given set of characters (following spaces). *

Space characters at beginning of line before the pattern are discarded.

* @param sequence the sequence * @param pattern the pattern to match at start of sequence * @return the first position after end of pattern if it matches, -1 otherwise * @since 2.1 */ protected int startsWith(CharSequence sequence, CharSequence pattern) { int s = 0; while (Character.isSpaceChar(sequence.charAt(s))) { s += 1; } sequence = sequence.subSequence(s, sequence.length()); if (pattern.length() <= sequence.length() && sequence.subSequence(0, pattern.length()).equals(pattern)) { return s + pattern.length(); } else { return -1; } } /** * Reads lines of a template grouping them by typed blocks. * @param prefix the directive prefix * @param source the source reader * @return the list of blocks * @since 2.1 */ protected List readTemplate(final String prefix, Reader source) { try { int prefixLen = prefix.length(); List blocks = new ArrayList(); BufferedReader reader; if (source instanceof BufferedReader) { reader = (BufferedReader) source; } else { reader = new BufferedReader(source); } StringBuilder strb = new StringBuilder(); BlockType type = null; while (true) { CharSequence line = reader.readLine(); if (line == null) { // at end TemplateBlock block = new TemplateBlock(type, strb.toString()); blocks.add(block); break; } else if (type == null) { // determine starting type if not known yet prefixLen = startsWith(line, prefix); if (prefixLen >= 0) { type = BlockType.DIRECTIVE; strb.append(line.subSequence(prefixLen, line.length())); } else { type = BlockType.VERBATIM; strb.append(line.subSequence(0, line.length())); strb.append('\n'); } } else if (type == BlockType.DIRECTIVE) { // switch to verbatim if necessary prefixLen = startsWith(line, prefix); if (prefixLen < 0) { TemplateBlock code = new TemplateBlock(BlockType.DIRECTIVE, strb.toString()); strb.delete(0, Integer.MAX_VALUE); blocks.add(code); type = BlockType.VERBATIM; strb.append(line.subSequence(0, line.length())); } else { strb.append(line.subSequence(prefixLen, line.length())); } } else if (type == BlockType.VERBATIM) { // switch to code if necessary( prefixLen = startsWith(line, prefix); if (prefixLen >= 0) { strb.append('\n'); TemplateBlock verbatim = new TemplateBlock(BlockType.VERBATIM, strb.toString()); strb.delete(0, Integer.MAX_VALUE); blocks.add(verbatim); type = BlockType.DIRECTIVE; strb.append(line.subSequence(prefixLen, line.length())); } else { strb.append(line.subSequence(0, line.length())); } } } return blocks; } catch (IOException xio) { return null; } } /** * Creates a new template. * @param prefix the directive prefix * @param source the source * @param parms the parameter names * @return the template * @since 2.1 */ public Template createTemplate(String prefix, Reader source, String... parms) { return new Template(prefix, source, parms); } /** * Creates a new template. * @param source the source * @param parms the parameter names * @return the template * @since 2.1 */ public Template createTemplate(String source, String... parms) { return new Template("$$", new StringReader(source), parms); } /** * Creates a new template. * @param source the source * @return the template * @since 2.1 */ public Template createTemplate(String source) { return new Template("$$", new StringReader(source), (String[]) null); } }commons-jexl-2.1.1-src/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory100644 0 0 1562 11673634325 27050 0ustar 0 0 # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # org.apache.commons.jexl2.scripting.JexlScriptEngineFactory commons-jexl-2.1.1-src/src/site/resources/images/jexl-logo-white.png100644 0 0 25776 11673634325 22653 0ustar 0 0 ‰PNG  IHDRæS‹m{}bKGDÿÿÿ ½§“ pHYs  šœtIMEÛ -à¿ÀmtEXtCommentCreated with The GIMPïd%n IDATxÚí}ytTEöÿ§;pÆùC‰tˆã3¢‡È"PQ„ $"#ãpÏ€ƒ pÆa\€Ž€";IdÙdÜ@"‹Ð ;²2d!* $ÝÔï­÷»ï¾[¯_P\æÛuÎ;ét¿ªºUu?÷Þºu«Ê§”Rh@¢¯70«-ù|¾×÷SªCçñZÏë–Ïí·†Ò*½94{¡U*—×¹ãé…æïÒ7¦ò¯$¹õÏ+0wíÚe=:]ýõHOOGFFš7o•ùôÿRc}>víÚ…3gÎ`õêÕ¶ß222‘‘ôôô¨êVcÕªUèÔ©222åb×®](,,´Ú˜““c«Û”Ö¬YƒÝ»wãÌ™3¶¼Æãôrº ±zõjL›6MlûêÕ«QXXhÕ™‘‘ÜÜ\ÇxHý°{÷n[_ë¼)))žè5¯._÷£¦ RRR¬z¢±^4Ðë¾ÉÍ͵ÆR—©ùH#äää 777j}n<ÄûrssÑ©S'«ÏŸxâ L›6Í(¼Ýþ·>«(é…^P))) €ë“““£N:¥jkkO(R¡PH…Ãa‰DT]]ª««SÓ¦MóTGJJŠ>|xƒë‰D"jÅŠ*77×*kÅŠ*‰¨p8¬B¡Ú±c‡JOO7Öžž®Nž<©.]ºäx¦L™âJ¿Î[SScËWSS£jjjlt‡Ãaõé§ŸªiÓ¦©ŒŒ « M«¦wêÔ©®u>þøãŽú.]º¤Nœ8¡üq×~Öyõ#ÑJé¥cùþûïÛèŽÆ3Û·oWµµµ¶ú¤ñÔmß¹s§1b„­í¯¾úªÕ/ÿùÏÔðáÃ]yhéÒ¥Ž~1…nßÈ‘#meäææªÜÜ\[[srr,òÊ—ºßêêêT}}½ª¯¯WJ)eæ®]»l9r¤Ú¹s§Õ§NR999ކ/Y²D}õÕWŽç믿¶:@º|ùr[#FŒP;vìP¡PHÕÖÖªS§N©çŸ^dÀhõœ}ÚFHmm­UqÇŽÎÏÏW_~ù¥õœ?ÞÖø¯¿þZM™2ÅZ¾î¬Þ½{;êÉÎÎ6Ö3lØ0Õ»woÕ§Oq`–.]ªŽ?nÑß¼ys5tèPõÊ+¯¨üü|õØc‰ù&Nœ¨Î;§-Zd}—••¥òòòT~~¾•WìĉÕçŸn{¾øâ õå—_ªŽ;ªÞ½{‹ý©zéÒ¥V¹;vT“&M²êLKKó:tH;wNeeeYí2dˆÞììlc^‰VÝÏz,9 rrrl¼¢µ®ÏÅ‹‹‚ëÈ‘#âxöîÝ;êX.Y²Ä6ŽÑÆ¢yóæêܹsÖÃÛ§y•Ö©µ»©]´*%ÁF…·:D`RP¦¤¤X&%䫯¾R/^TçÏŸW“&Mr4ºY³fªººZUUU©êêjU]]­Î;g5ü•W^qt,•0ºü .XƒôÅ_XÌEŸ¬¬,«]ÏçŸnå3i ô´´4µyófõùçŸ[eTUU©ªª*uàÀ±m .TTff¦Ú»w¯*//·žŠŠ UYY©öï߯š5kæÈKß-//W•••V?Qšè}ì±ÇÔáÇչsçôN˜0Á‘ïÑGU™™™ €?~¼Hkee¥zùå—żÒûÕÕÕVòÉ'6†ìӧͦãyþüyk,óòòľ=pà€c<)`$­ëÏÎÎV´ú¤²²RUTT¨ŠŠ Õ¡CG¾… º¶oË–-6kIk?‰OÏŸ?o{_hô œ6çÏ®]»Ð¹sgk"úÙgŸ¡Y³fPJ¡¾¾õõõÖgý÷Ì™3hݺµc’¼`ÁdffÚ>Ÿ{÷îE÷îÝ­÷:vìˆwß}×æØ ®K?mÛ¶Eii©XuHøý~øý~ý]øÚk¯ç4feeaÑ¢EbÛt?~<,Xàh_Ïž=1gÎÛ¤>š®ñãÇÛò­_¿íÚµ³þ×4jzãââ°~ýz 8ÐQç¢E‹Ð«W/­”Þ´´4GÿÀœ9sгgOWz{õê…¢¢"ëäädìٳǑ‡ÒÚ¦M”””Xï?~Ür‚pùç±cÇbÞ¼y6:333±`Á]ºNŸÏgì›—_~™™™6^¥ü´wï^deeÇÖ¡Û7nÜ8Ì;%K–Àçó9xT× þóŸ±aÃTVV:<´lú™ÿ~ ˆ¾}ûZ1Âe]]êëëQWW‡H$‚H$‚p8Œp8ŒÄÄD´oßÞÑQ­[·F(²=ápÏ<óŒí½G}Ô*“>áp¡PÈVW8¶:ЦþóŸ…B¨­­Emm­•W× …âxž:`Á‚Ö{:/ý\[[‹{ï½×Q_Û¶m1}útÔÔÔŸÚÚZQ`>}ÚV¾~—Ò]WWçÈ7aÂôìÙÓF/§µ¦¦Æ&ôtzꩧЭ[7‘FJCÛ¶mmùÊÊÊlåÓ> …B˜5k– ”ÙÙÙHLL4ާ~ô¸Œ3ÉÉɶ:7n܈ÂÂB[]4Ô7ãÇÇý÷ß/ö‡n[Ë–-‘””dËWTT$Ž…®‹z^?üðC«-ºm‘H¡PÈ~”ÿ¤þ¨««³pÅ…ˆ ˜Ó§OGqq±Íµ¬ÁX__/¢;zΜ9¶ž9s&š6mêŒÝ»wÛ$²–Z¼<ýèÆÒïZ·ní̲²2ÌŸ?ߪ‡2Ï·àöóÁLJJ²~×BRnÙ²¥ƒ‚Á +(u©©©Ž¼›6m22{MM˜Á`Ð!D$pÝrË-޼ ¶6éçÒ¥K¶2ZµjåÈ»aÃGšÎùóç;´ ˆ`ú=zˆ@£ãGiŒD"Ž÷›6mjõKCåÙ³gïÐÏ0PRR‚™3gÚx“¶S·K F©805¾$ë' ‘ºjÕ*Ñiii6Ds”Ó¯»î:ìܹ%%%HJJ‚R ápرÖÈMÂvíÚ9:Z2—¹4éÞ½;òòò ß¿›YBžêëë-ÌÛDë’Ö²êëëg2‡xª««CMM-O\\œõhi,å£ôjš)½>ŸỎDPSSãX7äfT8vä ‡Ã6zµ »iÓ&”••ÙÞmÓ¦ B¡eîiú8óÑñ¼ï¾ûðòË/ÛÊÙ·oþûßÿZŽÒ)щDP[[kõ ï:n<ÕÖÖ:L͸¸8D"´nÝo¼ñ†õîØ±cQ__AƒÙLf:RJaåÊ•V?ð©•.ŸÖ©é¢fr@)…ââbÛBlzzºU™n¨F:Õ¢<Á`‘HÄakÞzë-Qkiâ9 iÇÒ¾÷Þ{ÀÜ¿¿mÐ88MàÒmÓíäƒif(²™!£›"aB¡­_|>€õ˜À¥i¢×L-Ñ)0øœÇL]¯¦W¿K–k.ÚOÑÆ³U«VHJJÂÙ³gfæ=÷Üã ÕÔ7Z›š€éóùDK„ÒKЭ[7<÷Üs¶÷LJ 6`ôèÑhÓ¦ØÆÔÔT„ÃaÛørPò@¿ßoÃL>øà[åÍ›7AIÁÉ¥5wÜpMWQQ!28eÓÄ7B2¹`ïÞ½¸å–[LD;ä1õ_^§`Zó‚oÁgý5µ™‚ßï÷Û¤}4IÁI…ŸfRS^Ê<\C˜WçåÌˤµ‚\£Ðñä‘.­[·v”·oß>Üu×]¶±ðûý6Z(¸80ußÐz$IÇB÷‰¶\š4i‚‡~K–,qðYŸ>}жm[¼ð ƒ¶6JN«¸¸8G[$Üè€Ý»w;¤:ejKVžWGÁûñNjڃÓxÝÚy‰‰‰(//·•WZZŠ›nºÉ‘ÏMcR`Òú£i=j=Ð>Ѓ'2‚ÎËÛ¬ïLZÏUôXжJyõT„ Ê„Z8˜òR¦óù|8tèÉú¡‚Zò'&&:Ê:{ö¬Z¯Wk‚ò(Ïksº|ÛšöáÇãìٳؼy³#ï¾}ûЭ[7ôïß=ô‚Á ÑÛÎ}$ÚJ)›÷‰Srøpfänm>çr‹‡¤ƒ.Ùê¼SiÛ´iƒwÞyÇ•é©V0i.ÚNÞ.¨5£Qf§åjz%É—žø÷ºïM}EJëÖ´J€N?¸ ©¯¯·æ·¦¼ ¥¤5¦i)ký]›6mZ‰®Ðün¦,Õ–´ºo$^ä~ɬœ4i±téR±ÝË–-ÃæÍ›ñàƒ¢_¿~kMÒÜ\qËÓ/Uôá‡:4&÷.q;^š³ðuž6oÞ,–ϵ‚d–˜"üé²õš]ò˜™ê•,7ç˜Äè4/5¡yÝnÀäæ7ŸWE£Õ”×D¯äoÒ›o¾éX"3™ßln‚›ò .K—ÿH‚Ð$|¤©[$ÁðáÑ——'jw¨¨¨ÀÌ™3‘’’V8’ùJ-P¿dŽ–””5¦4Á–¼ZzgÔ>ñññŽÈ 8xð hb™œÔëIS«V­Zš™&`Jábј†NîÝÞ‰Æ&íMª»Ë­N7ZMyi;©„oÒ¤‰ãÝÇÕùÔÀm,£g´y0wLFGj™ /·iÓ¦xì±Ç°råJtéÒEçÊ•+EeC±c2oýzóª´ôPTTä˜éÏ’çT›­o½õ†êIkj`òå“ö0­‰ÞsÏ=¢ÉfLéwѤÌ,>w–ßd¢™æÝRP…m,­•I̧`zLÓ^‡¦ÆTëTUUei ·9/÷í·ßv„s&%%ûÇmZ *7¡dr^*¥0yòd¬Y³Æµü¦M›b̘1xúé§eoß¾]´£Í;-™žž.îx>|8JKK ‘æBºQûöíÃ!C0þ|0iµN‡¡C‡\#)¸9"­¡ÝsÏ=¢ôs3Ü’j 7pñ:½0:´›Fôj&{ÑÜ<*)cr¿ñÆ‘àxÿõ×_çg¦¹·4ž÷Þ{¯ƒ&)Ð$0)½&õH}xäȱ\þtéÒÙÙÙAå'K­Çš¸.dذaâZÒ /¼€²²2ã܆¯U2íÛ·G‡l.㸸8tèзÞz«£ž÷Þ{O¦iM“kË 99Yˆi0£™r^LY“Æ4 ²iP%FóJ¯$L‚„Ó&Ñßùôïÿ{Çû;wîŒÊ'œÇèwRRþô§?9„^´³wܬ‰†ŒO;vìyDê»Þ½{S’‰oò¨Û–K† &jÍ-[¶`ðàÁ8xð ÑÔ¬¯¯G^^rssQVV†yóæ‰Ë'~¿³gÏvÔ±råJ+2(š×P)e ÇKNNÆSO=e†—Aõª]L棛9ÛPçQC“—vJf.§Û¤QÜÚÔ³gO´hÑÂö~uu56lØ SZå¡•3fÌAy9ˆyí›hå¯^½Zsêìôûý¶¸é¦›\—`$YA”!&Nœh\£6lú÷ïyóæaÛ¶m(((ÀÖ­[1}útÜwß}˜2e `öìÙHNN6J°f͚ᥗ^rüöì³ÏŠó?îRÎÏÏ·‚§“““­à{7pDsx¸ÂäÕùÃëñª¾Ë‰u^ê“b2¥ö^.óŽ9ÒaÒ¾òÊ+¨ªª÷ÓÒçìÙ³6`Μ9·Þz«±]^i”ò˜òJý!³¢¢BT6œçγåëܹ³Ã»ëfÖR¡e“ÙÙÙX¸p¡‘ªªª°nÝ:Lš4 Ï>û,Ƈ+VX¡qÓ§OG÷îÝ£®öèÑÿú׿lß=z“'O6z*•Rxûí·-œœŒÕ«W#99Yd<Úy¼Ã¼Ì¯ôo|ëž_.PÊËË£O)Õé >ŸUUU"½&&´%cz/!!“&Mr€sôèѨ®®­ ʇzÈzÖ¬YèÑ£‡8—£c©Ët—  ‡npû´‡uÖ¬Y­©5¥æë¯¿nå¹í¶ÛlsN·É’ðs¢²²²l;ó½¤`0ˆçž{wß}·( ¤éÞ½;–,YbSÿ;wîÄ#<‚ 6ص  ùË_ðüÀ7•W®\‰¤¤$ѹCÁçÒ×uUWW»j:ŸÏ‡÷Þ{OÌ‚‚‚¨våÊ•"H¤€~·y Ƕ<“–/((päݺu«+êï$z·nÝU($$$`òäÉèÔ©“ͤ2d–,Y‚ãÇ[cyøða¼ôÒKèÙ³'ÊËË‘””„—^z ÷ß¿”œÿþ÷¿4¬_¿>ªé»mÛ6QàIý%¥‚‚<òÈ#8xð D3wî\ë(Ð;î¸O?ý´cŠÀpsùÂá°¢á^zCê§Ÿ~Š¡C‡âÀ®çää _¿~HIIA£FШQ#kÝ’ïì‚ãC¡/^Œ+VDÕ­ZµÂ¨Q£Ð¾}{KZé†ÐMÒáp[¶lAEE¶oߎO>ùD,ïºë®ÃÍ7ߌÎ;Û¼Œ'OžÄñãÇñþûïãèÑ£Fzî¼óNÜ~ûíhÒ¤ ~ûÛߎ;†'N`çÎÆ¼Á`wÞy'Z´h&Mšàšk®Á±cÇpìØ1¼ÿþû¢Ö€–-[âæ›oF‹-,3 øfwЉ'°cÇcƒAtéÒ-Z´@‹-píµ×øæ8™ãÇ»æMMME—.]píµ×â7¿ù ®¹æG(¦~Ž;†E‹Y`tæ?ü0hñ A¦›Â÷ïßC‡aíڵƾ¹îºëйsg´hÑÂÕÕÕ8yò$>øàìܹÓHKË–-qÇw sçÎVÛ|>¦NŠêêjƒAøý~ ĉ‰‰Ö¦k¥¶lÙbµé@Ÿ>};±è²U||<5j„«®ºÊöPüø¾=Èæ9Ò;¹/]º„Ï>û EEEx÷Ýw-픀-Z K—.Va7¶hϨ¥úB¡öï߃ÚÚï÷ã®»îB›6mpýõ×Û€¯Ëä!}¡PcÇŽ5n“Ì«¬¬,Üxã¾9ÞâøñãFÏ ÷ ßtÓMèÕ«”RذaŽ;5¯þ«²~ýzѱ$-§(¥0jÔ(«mS§N5®­JŽ4ÚÖ†æÍÌÌÄoû[GÐ7§µ¢¢Â4´ÌÔÔT´nÝíÚµ³¥àZpÓ±\¾|9>ì9Äñ‰'ž€R 'NœÀÆqÛ¼}º_t='Nœ@RRš5kfÑzäÈTVVâàÁƒÖ2O0Ä-·Ü‚®]»Šëþ¼¯4f7nl²qãÆÖc&en­5/]ºd?¡[ ç®ÐM¥špÚÙZò£9üø B§%L °ˆÖeëæñ¶TZñ½’<íDÚyqqq¶6i!ÃŽ¥QP4â‰ZT(ñslt^)ΘƢrIL£­4­4¯n§äª×ý«ûS·W SÝVJ+ ¯£ËFÏiH@1%Z2s´ÉL%a4À5$pø`J»8³R†3P—G¿çáslžWÚÏJ]ç§ÌC¿£‚„[RÜ0÷JÒ››ù´_ùœ˜ö—dÎòiŸ?KÖ=nE² (ÿѱ¦¼*i'Úo|ÌøÎSßòxc.|¨àLPÝÿnSs/ гQ¤Å`7‰Í'Ï\øÛB· ¹…’™Ƶé#™*´sMƒÂç§tÁ«;œ:ª$ÁÂn¦!§•;è Ó±åÚ%š§y©†”,ÚV.ÀL[êøXz±ˆ$Ÿƒž_RÞá™ûJ¨ÆÔÓ,ÓXH~7Z©öäB‰ò#&¨I›iI"íΠ‡>q­IMÎ(ÜÛ(…v„Û©uRŒªä˜‘­ø¼•›Ö&`rMÀë¡oÊ+E©ðzÝN÷ÓšV2í8¸¸#C2¿h^Ÿ×KÇ–·U²,¢™³|.m»€9iÜm´ÜH$â˜IÎ ,ýü|,¸€å&¯ëÍj4&@@€Ï­¨SJ!>>^ÜÜ*- Rg€T1g:¿¢æ«>eŽŸã%Ë-ŽUw=N?Òz“2ÒúÍÇój‰ÈçÜ)a:ÖmM±®®@@<Ï–ƒƒÏè]R}´­’0ˆ–W2…¥ÐJI˜+&Lûƒ¶Ÿ®HcÉ5ºnŸ4¼_u~ ˜n§Eš,IyYücò^*¥jÞ 0%&¡•»™’ÂêLóN. ¤Ãž¼‡á6oáà4[" 9.ÐL¦¨I@JA %TJY€o‹‹³®O”æÂ´ÿ%³—Z?THFK·£ín¡sᢢ"Œ=}ô‘µ„{’M'uq‡¦QcÒù¦ät‘L“7™Y¦…fMäåžZç˜TÒRM":˜<¿¦ý¢nRßÍ!m×?Úa:ÒÄt¥…Éâp[þâÂÑ4®\èjPêôÆo OŸ>Æöp@JƒñC­ø˜DÛ—ée¹À_¿~=Fm»‚:ýLSqAÏ-ÚwÎà\sòµÊÐ’6sÛéêF¦±Ýæ&¦Ï(hGiÍlwLxñ¾yÙ9ÍsÍëçe§>n1ÍóJ¯ò楌æÍ›Û˜9%%EùäÌš5 O=õ”£/Ü€i2‘h%p»)¢Çt˳—E ý2]° ˜Ñv¹›ÞµkW””” ;;ùùùž’B¹È×g½ðÉ包[ˆ¢ÎsõÕW[ïççç#++Ëx¨ß'Lg|&F§ ç’@²Ñ½zÙܯ%óÇë¡Änf 4<¼LÒún Û^€âf’rMæv‚$4Òöhô6$¯©¼ôý¯ýkœÊ»Ü£¿/ÐüéJÓëõ=É%]p˃Á9Kð†­¡R¥T¿ƒ†“žÔ@ÁʃñWzp¿¯ã¿/Æþ®ôüïç˜"TÝœc\kr_Ÿ™üW²^@)]ñA}:f̘à›sŒ}ôQG°ÕŽeeeX°`æÎ‹´´4¤¤¤ ¸¸{öìÁš5kéééX¾|¹ír,]Ö‹/¾ˆÝ»wÛèHIIÁóÏ?ï¸ç³¾¾«V­²ÊÕe>ܱþ+-‰ðë90¥ðVãú°ŠÙf±t…5fqq1úöí‹ÂÂBÛoÙÙÙX´h‘x=;”••!++ °hÑ"dddX ½gÏ<üðÖ†KIIAAAxÍÇÿøG¬]»Öú¿OŸ>X¶l™Q«ÿò—¿,]º999®‘P¿úÕ¯¬ßæÏŸîÝ»;®´:d7 =ªRfÛ”cXºÒ)%%¯½ö>ûì3Ï`.--EVVJKK±iÓ&tèÐÁŒŸ––f;Œº¸¸ýû÷¯!ÈÏÏ·víÚµ8}ú´ãj¼H$‚_|°xñbdggo-£€IS:-_\+iKÇm_±KWœ)))HOOÈ .\ˆÒÒR 4ÉÉÉ6PjæOLL´]C°gϬ^½Úq³V8vÜ×­[7Ç=ž§OŸÆìÙ³‘••…ÌÌLñM·»[©Ötý é"\ÏW½ÇR,])€J ¤Œ[ZZjݡӳgOùíY½zõ²•·víZñšù`0ˆñãÇ[ï•””`À€¶÷î»ï>´k× ,°£+”ŸIE5¦DÓÍѦ™dÌùK?Èþøc¼øâ‹HHH@mm­õ¾iÛ™—½¾nÁô˜yŠÍ1céG'¿ÿƒ&:ÇÓ÷ÛЇÞ{Ã?óGß“ššŠQ£FÙêyã7låêû{x]üšv·6¹9¸L ŒyecéG +ËiïÞ½6@H`£ ÑàssÜD"Ü}÷ݶzÞyç¼ùæ›¶2ùãÅùãȆ¤0céGM|y^N¥ÍL%Í(yOù纺:<ñÄhݺ5­ºž|òI”””8ê Ú˜‚Òë¶±†îÖ‰3–~RóLÍð,K—.¯k䦥~öïß/+JŸQ£F¡¼¼Ï=÷òòòlô 4ÈVž ìüØÖï;Å€K?(Mæ-]tOMMµÞ©¨¨p€Ó ,3fÌ0.Y(¥°lÙ2lÙ²yyyHLLD0ÄðáÃmõ;6j`—âbÀŒ¥ÿ‰¹§Öš]»vµ½3sæLlÞ¼ÙîˆyõÕW‘ššj<ŒkëÖ­˜>}:¦L™‚äädËÌìß¿?~÷»ßYïoÛ¶ Ž:)4¯¡Éó›1Öˆ¥Ÿ0•RèÚµ+š6mj{oܸqX±b…cΨŸ­[·böìÙxàls;½¼QUU…éÓ§ãoûºwïn;Ëï÷cĈƒV}Ï>û,***l7Us9fÊÆÒÿ pÒ9§X0wî\<øàƒ˜3g PPP€U«VaèС?~<xàƒAñr¦ à¸5Ýçó!)) Æ ³Õ7qâDñà07SöûÚ¬ 0ˆ¥Ÿ¤ö¼óÎ;1vìXL˜0ÁöNee¥m¿¤N]ºt±™‚óÉ'ŸDyy9þþ÷¿;î?þÿ=™wß}7V¬XÇŽ=ŠùóçcðàÁâ'¥¥¥6Ξ=ë4—;ïŒiÌXúɦ.]º`ôèÑQß»ãŽ;0fÌÇAk•••xòÉ'±eËÀPQQ!^Bë÷ûqøðaTVVÚÊ~ýõ×±`ÁTTTØ´fYY¦Nj{7??û÷ïwuvyž‹Æ6JÇÒ¥ëêêð‡?üÁÚ´œ™™‰Y³fYQ6:Ò&ÛæsX»v-Ž=Š£GZeß~ûíèÓ§Z¶lé¸ú1..Ï<óŒx÷æÀѶm[›Ã)//û÷ï—XtêÛ·/Zµj…5kÖàÈ‘#®W}<÷ÜsˆD"¶âââom’nܸ±môí°ëÄÒO9ù|>ƒA <ØtIÑߦL™"Þ Î¯QJaÀ€âº%?ƒ|ðAÄÇÇ;nƒæk²ÒeI¼m&ó6ÌXúÑ?ÄíB(~«ä|1àoºƒ„IE4¯)ÂÇä™5-ÕHmŒ9bé'™Ú·o/jÓý6ü6:·yœÛ•ü fé‚)é4uIHÚžß%j:üs ˜±ô£¥:¸jéžMÊð’V”æ¶ÑLe~3Ý^&]UèV&5™ùå´n3–~””––†fÍš‰û©ãL+]½G߉vy±¤…ùÒHtžÈoÒ6^ŸGN×ùµ{4°!6ÇŒ¥%Ûæ’{öìðMd›iiÒBTJ—&KK!¦Íδ,z£3U\\œ5Ï”.gæ·MÓ90w2ñ[ÕÝNFˆ3–®hêܹ3NŸ> X³f Š‹‹±xñb¤¥¥!;À'iJ‰yùWú ués "~Ü%Õzú¦2nNóË™¥y,²IppMf,]qyà 7 ##………Xºt)²²²,Pš<¦Òµèœù¥õFzÁ-ÕR¨ |îÊËãáwüŠ7“Y¢Éï÷ÛÖYÝB1`ÆÒKJ)ë~œœ,[¶LÜ ÍhÒ4TCIÇ@R­'Óte<»J¦2¿‰Ì œèüžM'5¡mšó'ù£ÈcóŸ'0©6âgÂÒÍÏtaŸFËè‡.äKuðKo©§ÕÍtt£Y(‡Ë 7Ü`´ôº³gÏFvv6ü~?Ö­[g]¤tþüyã¼óç’§‹íý&ÝüL¯¦£Ú’GîHK&Ò|Uk)nº]ȵ¿ìHò'%%ÊËË­ßôI 7Üp>øàø|>têÔÉšsõÕW¢©þsºíË÷í£¾ý[Ó¢?_°J¢ëˆ|m‘ÎMZSrÌPS˜;¼ÞL?smi:’2pB* aÉ’%`sx¹iðŸÛSSåÏTsro«i‰ÄäÀ‘ÖÝÁŠæ¤iý^âããß;cÆŒLš4 ƒ r˜Ü\`Äv—ÄÒ$Õ8ü,~ÕzÑ€éNéÖj0% J!y&!W_}µežòï.^¼ˆÛn» >Ÿ»víÂ/~ñ K{JK%?§9f,ýÌ)!+:çLú¿sÔo{9Óí¸êª«ÀŠd€Æ;¾óù|hÔ¨ØÎ¥­cÆÒ?ÿ`;C(òy¥›)ëÕ³jböË¥pòž¨SÇ+1`ÆÒR‰¥ o)¾”¯ûyÜw=JÒKÒu ¦+ô÷nލÿ§ÐIúSY[~IEND®B`‚commons-jexl-2.1.1-src/src/site/resources/images/jexl-logo-white.xcf100644 0 0 51630 11673634325 22633 0ustar 0 0 gimp xcf fileæSBBLS gimp-commentCreated with The GIMPgimp-image-grid(style intersections) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) Î3 4j(’Qµ TMÿ     ÏHLgimp-text-layer(text "TM") (font "Sans Bold") (font-size 10.000000) (font-size-unit pixels) (hinting yes) (antialias yes) (language "en-gb") (base-direction ltr) (color (color-rgba 0.000000 0.000000 0.000000 1.000000)) (justify left) (box-mode dynamic) (box-unit pixels) š ® ¾ÐÐÐ0ÿöÿÿYYÿÿÿÿùÝÝÿÿÿÿùämnãÿÿÿÿù_êê^ÿÿÿÿùÎÍÿÿÿÿÿÿÿÿ/>'jexlÿ     ˜$JÔ>'è>'ø r r rüªU0ü8ª8þªÿÿþU-ú8ÆÿÿUÿþª+ýUâÿÿþUþâÿÿþ+üqÿÿþUûâÿª/ÿþU8ÿþU8ÿþU8ÿþU8ÿþU8ÿþUüqýUªªýq8þUUþ8UUÿþUúÿÿªùÿƪÆÿÿýÆüUÆÿÿýâUý8ªÿÿýÆUÿþUýÆÿÿþªûââ8ù8âÿÿâþªÿÿþªÿþUÿþUÿþªûâÿþÿÿþÆþâÿÿþüqÿUÿþUûÆÿÿªüÿþªÿÿþUþÿÿþâüâªÿþUûªÿÿªûÿÿ8þUÿÿþªþqÿÿþªý⪠ÿþUûªÿÿªüqÿÿUUþÿÿþªÿÿúqªâ ÿþUûªÿÿªþªÿ ÿýâÿÿüÆâ ÿþUûªÿÿªÿþ8ÿÿþU ÿþUûªÿÿªÿþqÿÿþª ÿþUûªÿÿªÿþ8þÿÿþU ÿþUûªÿÿªÿþqÆþâÿÿþ ÿþUûªÿÿªûâÿÿâ þ8ûªâÿÿþâ ÿþUûªÿÿªþªÿÿþqþÆùqÿqÿÿþªÿþUûªÿÿªþUÿÿþUýqüUÿUþªÿÿþUÿþUûªÿÿªþâÿÿþqüUÿüâqýâÿÿþÿþUûªÿÿªþUÿÿ÷âUUqÆÿâþUÿÿþÆÿþUûªÿÿªþUÿÿþªüªÿqþÆÿÿþþÿÿþqûªÿÿªþUÿÿþªùªÿÿªý8âÿÿýýªÿÿýâ8ûªÿÿªüÆÿÿýª8ªþ8þqªªü8qªªûªÿÿª8ûªÿÿ8ûªÿÿU8ûªÿÿ8üªÿÆ5þüâÿ85ùâUÿU6úÿâªâU7ªþU9\EDrop-Shadow#2Ì     ‘K Þ\E ö^\E ”>NR7þ2/üú þ ÷÷ ÷  ÷þê üõ õ ýè  üç  ûæ  úô õ û ç   ú õ !!ö ú õ  ""÷        ú ê  "##!  ü ûã !#$$# ýûë "%&&%" úúüê  $'))(&# ù "#$$ý#"!!"#ô"! ë #'*,,+*'%#!!ó#$&')*+,,+*)((ý)*++ø*)'&$"!  þ!ò  %*-00û.,*(''ø(*+-/0233ü20/..î/0123321/-+)'%$#$ë "(-1455420/..ø/124679::û987544û578:;;õ9752/-*('&ì %+159::98655ø689;<>?@@û?=<:99î:<>@ABBA?<952/,*(Æ  '.49=?@?>=<;;<=?@ABCDEEDCB@>=<<>@BEGHIHFC@<73/,+ì ")18=ADEDDCBBúCDEEFGGúFECA@>>î?BEHKMNNLIEA<72.,ð #+3:@EHIIHIJøIHGFDB@>>î@CFJMPRRQNJE@:50-ð $,5=<=?BFJORUVURNIC=72.ï %-6>EJNPQQRñSRQPNMKIGEC@><::î=@EJOSVXXURLF@940î %.7?FLPRSTTUVÞUTROMJGEB@=:8767:>BHMRVYYXTOIB<61Æ %.7@GMQSUVVWWXYYXVTPMJFC@=:754347;@FLQVXZYVQKE>83ê %.7@GMQTVWWXYZZÞYWUQMIEA>:74211248=CIOTWYYWSMGA:6Æ %.7@GMQTVWWXYZ[[ZYVRNIEA<9520../26;@FLQUWXWSOIC=8é %.7@GMQTUVWXYZ[[ßYWSOJE@<841.--.038=CINRUVUSOJD?:Æ %.7?FLPSTUUVWXZ[[YWTOKFA<730-,+,.26;@EJNQSSROKFA<Ú %-6?FKOQRRSSTVWYYXWTPKFA<830-++î-038EJMOOPÛRTUVVUSPKGB=830-+**,.148=ADHJLLJHEA=ð $-5=DHKLLKÚLMOQRSRQNJFA<73/,*))*+.148;?BDFGGEB?<ñ $,5@AAü?<:ì $,4;@DFFECA@@üBCEGGâEC?;73/+(&%$%&')*-/2479:;;:86Ù #+39>BCCA><:99:<=?@@?=:73/+'%#!!"ñ$%'(*-/1344321Ú #*17<964212356787530-)&# ð!"$&(*+,--,*Ø ")059;<:740-+**+,-.//-,)&# ÷ "$%%þ$ä "(.368752.*'$#"#$%&&õ%$" øþØ  &,03431-)%!öè $),//.+($ ÷   ÷ç "&)**)&#ú   û  ç "$%%$!  ù   æ  !   ç   ç  ç   ö ö &÷  õ 'ùö)üú+03i«  üþü ûùù  ö ø õ ø õ ê  ê  é "$%$" é  $(*+*'# é$)-010-(# é"(.25651-'  é%,169:950*# é"(/5:=>=93,% è$+18=@A?;6.' è!'-3:?BCA=70(  è $)/5;@CDC?91)! è#&+06BEFEA:3*" è)+.38>BFGEA:3*" è*+/38>BEFEA;3*" è+,/38>BEFEA;3*" ,ê/38=BEFEA;3*" -ê/38=BEFEA:3*" -ê/38=BEFEA:3*" è/.048=BEFEA:3*" 0ê149>BEFE@:3*" è2135:>CEFEA:3*" è5347:?CEFD@:2*" è7568;?BEEC?92*! è977981)! è:889:5.& è98779;=>=;72+$ þ755ì689:973.(" þ422í45542/*% ý/.--î.//.-*%  é)(''(())(&$  ý#"!!"ñ!  ýñ þò ó   õ þ ÷     ó@@@@ŒŒŒŒ."×commonsÿ     ×*(z(†×FK"I&ð€€€ý8qªªüUý8Uªªýq8üq8ýqâÿÿýª ýqâÿÿüâ úUªÿÿUõ8âÿÿ8ªÿÿþUôUâÿÿ8qâÿÿþUüqªÿÿþUúUÿÿÆþÆÿÿþUþqÿÿþUþªÿÿþªüªªÿÿüUÆûUÿÿâþqÿÿþâþUÿÿþUþªÿÿþªþqÿÿùªÿÆ8ÿÿþþÿÿþUþ8ÿÿþÆ þâÿÿþUÿþªûâÿÿþÆÿÿþþÆÿÿþU þ8ÿÿþâÿþÆþqÿÿþ8úâÿÿUþ8ÿÿ þâÿÿþqÿþªþÆÿÿ þþªÿÿþÆ þÿÿþÆÿûªÿÿþÆÿþª þ8ÿÿÿûªUÿÿþªþÿÿþª ÿþ8ÿûªÿÿþªþUÿÿþª þâÿÿþUÿûªªÿÿþªþUÿÿþª þªÿÿþUÿûªªÿÿþâþUÿÿ þªÿÿþUÿûªªÿÿþUÿÿ þªÿÿþ8ÿûªªÿÿþUÿþU þªÿÿÿûªUÿÿþÆ þ8þâÿÿþ þªÿÿþÆÿûª8ÿÿþ8 ýUâþÿÿþÆ ÿþqÿþªþâÿÿýâ ü8ÿ8þ8ÿÿþ8 þÿÿþÿþªþqÿÿýªü8âÆþÆÿÿþ þqÿÿþÿþªþâÿÿýâ8ûqÿÿþÿÿþûâÿÿâÿþªþUÿÿýâUUúâÿÿUþUÿÿþÆúqÿÿâÿþªþUÿ ÿþUþUÿÿþªúUÿÿâþÿÿþªþUÿ ÿýâU ý8âÿÿôâqUÆÿÿÆþqÿÿþýÆÿÿý ýqâÿÿýÆ8üUqÆÿÿýâªýUªªýUý8qªªýU ª€€€ù8qªª8ùUªª8 ý8ùUªªqùUª8ÆÿÿýÆýqâÿÿýÆúqÆÿÿýqâÿÿþýÿÿþÿÿþÆý8âÿÿþâü8ÆÿÿýÆÿÿþqþqÿÿúâUUÿÿùqUÿÿªUUýâÿÿþqüƪÆÿÿöUâÿÆqUUÆÿÿùªÿâUUþ8þÿÿúâUÿªýâÿÿþâþÆÿÿûªÿþqÿÿûªÿq þÿÿþªþqÿÿþ8þUÿÿþUþâÿÿþU þ8ÿÿþÆþ8ÿÿþUþUÿÿþqþÿÿþq ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU ÿþªÿþªþUÿÿþUþUÿÿþU þÿÿþâÿþÆþqÿÿþUþqÿÿþ þqÿÿþUþqÿÿþþÆÿÿþÆþÆÿÿýâøU8qÆÿÿ÷ªU88qÆÿÿ÷âU8UâÿÿüÆUüUâÿÿóâUUª8qª ªûqqª ªýq8ª ª ªü8ª€€€ªýqüUªªýUü88ýqªªþUÿþ ý8Æÿÿýª8 õ8âÿÿUÿÿýâUÿþ ùÆÿÿÆUýUÆÿÿþªüUªâÿÿûU8âÿÿûUªÿÿþú8âÿÿªþUÿÿýâªÿUøÿâUUâÿÿþâþUÿÿþúâÿÿªþUÿÿýâþªÿÿûâÿªþÆÿÿþUþÆÿÿþâþâÿÿþþÿÿþªþUÿÿþUþ8ÿÿþªþÿÿþqÿÿþª þâÿÿþ8þUÿÿþqþâÿÿþâþUÿÿþUþâÿÿþU þÿÿþÆþUÿÿþUþªÿÿþUÿÿþUþUÿÿþ þ8ÿÿþþUÿÿþUþªÿÿþUÿÿþUþªÿÿ þâÿÿþUþUÿÿþUþªÿÿþUÿÿþUþÆÿÿ þªÿÿþþUÿÿþUþªÿÿþUÿÿþUÿ þÿÿþªþUÿÿþUþªÿÿþUÿÿþUÿ þUÿÿþªþUÿÿþUþªÿÿþUÿÿþUÿþU þUÿÿþªþUÿÿþUþªÿÿþUÿÿþUÿþU þUÿÿþþUÿÿþUþªÿÿþUÿÿþUþªÿÿþª þUÿÿþUþUÿÿþUþªÿÿþUÿÿþUþÿÿþâ þUÿÿþþUÿÿþUþªÿÿþUÿÿþUþ8ÿÿþ þªÿÿþÆþUÿÿþUþªÿÿþUÿÿþUþâÿÿþ þÆÿÿþqþUÿÿþUþªÿÿþUÿÿþUþqÿÿþâ þÿÿþâþUÿÿþUþªÿÿþUÿÿþUþÆÿÿþqþÿÿþ8þUÿÿþUþªÿÿþUÿÿþUýâÿÿþþÿÿþUþUÿÿþUþªÿÿþUÿÿþqýâÿÿýâúâÿÿUþqÿÿþUþâÿÿûÆÿÿþÆýªÿÿõ88ÿÿâUþâÿÿþÆþUÿÿüqâÿÿûÆqUý8Æÿÿýâqü8qâÿÿ÷âUUªÿÿ ªþ8ýUªªýq8 þqª ªþ8ªªVVV ýUªªúU óÿÿ⪪ÆÿÿªÆÿûÆÿâ8ý8Æÿÿûªÿÿ8üâÿÿû8ÿÿÆü8ÿÿûÿÿªýªÿûªÿÿâýUÿþªÿÿþqþÿþqÿÿþqþ8þÿÿýÆ8þÿÿýÆ þªÿÿý þÿÿýâq ý8âÿÿýâ þqÿÿýâU ýÿÿýâ ýªÿÿþýªqþUÿÿþ⪠þÿÿýªÿþÿÿüªÿqÿþÆûªÿâþÿÿþqûªÿÿªûÿÿªþªÿÿýÆ8öÿÿªÆqøªÆªªÿÿ⪪ÿýâqªþ8ý8ø8UªªUk 5õ8 Drop-ShadowÌ     ÿÿÿúÿÿÿú9):õ8)VQQ©õ8)r3Â>oIFU  þþþþ øúùù ô  í     ù  ò ÷ ø ø ×  øî ÷ôøí  !#$%%÷$# ó!"##$%%ù$" Ð  "$&')*+,,+*'%"!#$&'())*+,,ú*(&#!é !$&(*+-.0122ç1.,)&#! !#$'(*+,--./02344ú31.,)×  #'),-/01346787642/,)(''(*,./11223û568:;;û9752ß !&*-/12334679:;<;9742/..è0245677665668:=?ABCB@=:ð "',024566Ù78:<=>>=;97544579;<==<:9878:>á=;:99:<>ABCCB@=;988:=@EIMOPONKâ &-38;==<:8655679;<=>==å>@BEGIIHFC?;9779<@FKPSUVTRÅ $+29=@AA>;853223579:;<==?ADGKMOOMJE@;7556:?EKQVZ[ZXé  (08>CEED@<830..Ü024689;=@CGLPSTSQLGA;63237=CKRX\__]à $,5=CGJIGB=72.+))*,.1369<@EJOTWXWTOHA:40/04:AJRY^abaè '09AHLNMID>71+(%%Ý'),/26:@FLRW[\[WQIA93.,-17?HQY_cddà  )3=ELPRPLF?70*%"!!"$'*.38?FMTZ^_^YSJA92-*+/5=FOX_dfeà ",6@HOTUSOIA81*$!!#'+06>ENU\`a`[TKB91,))-3;DNW^cffà #-8BKSWYWRLC;2+% !$(.55-'" #'-471,)&%&'*.3:AJRZ_bc`ZSJA93/-/28@HOUY[[à !+6ALV]bdd`[TME>83/,*)*+.38?GOV\`a_ZTLC<610149@FMRUWWã (3>IS[aeec_ZSLE?:52/--â/27=DKRX\]\YSME>94336:?EJOQRRà %/:EOX_ceeb^XRLFA<741/./149?FMSWYYWSMF@;7557;?CGKLMLÅ !+5@JS[`dec`\WQLFA<741/./15:@FLQTUSPLGB=9778;>ADFGGFÏ &0:DMU\`bba]YTOID?:51.-,.04:?EJMOOMJFA=:88÷:<>@AA@?Ä !*3=FNUZ]_^\YUPJE?:50-*))+.27=AEHIHFC@=:87789:;;:98Ð $-5>FMRVYYXVRNIC>83.*'%$%(+059=@BBA?=:8755ü421Å &-5=DINPRQPMID?:4/*%" !$(,048:;;:875321100/.,+*Ø %,3:?CFHIHEB>94/*%! $(,/133ò10/.-,+*('%$#Ö $*059<>?><:62.)$  #&)+,,ò+*)('&%#" È !&+.134431.*&"!#$%%$$#"! É !$')**)'%" ò   õ ö ö Ú   õ ô é   ö  ö  ÷ ø øù "    þü      ú  ô      ø ø   ë  üø  ÷ ó ûöø  öî !!û"#$$%%û$#"!  !þ"##ø!ö !!ð"#$%!$&'))*û+,-.//õ.-,*))()*+,,ì*(%!"$&())**ú+,-.÷ #&*-/12334ü57899ú8764211ü23455í31-*&" #'*-01233í4567'%%&(+/369;<==<<ó=>@ACCDCB@><::ý;=>>ì=:62.)&$$%'+/37:;<=<<ñ=>@/--.037<@CEFFþEDDûFGIKMMÞKIGECAABCDFGFEC?:51-+*,.27<@CEFFEDDEFH86558;@DILNOOMLKJJLNPSUVVTROMJHGGIJLMNMKGB=841125:?DILNONMKJJKLN@>==?CHLQTVWVTRPOOPRUX[\]\YVSPMLLMOQSTTRNID?:778;@FKPTVVUSQOO€ÅQSHEDDFJNSX[]][YVSRQRUX\_aba_\XTQONOQTVXXWTPJE@=<=@EKQWZ\\ZXUSQQSVOLKJLOTY]`ba_\XUSRSUY^adfec_[VRPOPRUX[\[YUOJEA@ADJPV[_``^ZWTRRTWUSQPQTY]adedb^YURQRUY^bfhgea\WSONOQUY\^^\XSNHECDHMSY_bcb`\WTQQSV[XUU€;X\`dggfc^YTPOPSW]bfhhfb\WRNLMPTX\_`_[VQLHFGJOU\aded`[WRPOQT_\YXY[^bfhhfb]WRNLMPU[`ehhfb\VPLJKNRW\_a`]YSNJHHKPW]befd`[UPMLNRb_\[[]`dgiifb\UPKIJMRY_dggea[TNJHHKPU[_ba_ZUPKIJLQW]beec_YSNJIKOca^\\^adgiheaZTMIGGJPV]befd`YSLHEFINTZ_ab`\VQLJJMRX]beeb^WQKHGHLda_]]^adghhe`YRKGDEHMT[`dec^XQKFCDGLRY^ab`\WQMJJMRW]bdda\VOIFDFJda_]]^adghgd^XPJEBCFLRY_cdb]WPIDBBEKQX^aba]XRNKKMRW]adc`[UNHDBDHc`^\\^`cfgfc^WOICAAEJQX^bca\VOHCAADJPW]aba]XSNKKMRW]acc`ZTMFBABG`^\[[]_cegfc]VNHC@@DJQX^aba\UNHB@@DIPW]aba^YSOLLNRW]acc_ZSLFB@BF][YXY[^befeb\UNGB?@CIPW]ab`\UNGB@@CIPW]aba^YSOLLNRW\`cb_YRKEA@AEZXVVWY]`deea\UNGB?@CIPW]ab`[UNGB@@CIOW]aba^YTOLLNRW\`bb_YRKEA?AEUTRRTW[_bdda[UMGB?@CIPW\`a`[UNGB@@CIOV\`ba^YTOMLNRW\`ba^YRKEA?AEPONNPTX]acb_[TMFB?@CHOV\_`_ZTMGB@@CHOV\`a`]YTPMMNRW\_a`]XQJEA?AEJIIJLPUZ^``^YSLFA??CHNU[^_^YTMGB@@CHNU[_`_\XSOMLNRV[^`_\WQJD@?ADD€2EHMRW[^^\WQKEA>?BGMSY\]\XRLFA??BGMSY]^][WRNLLMQUY]^]ZUOIC@>@D>=>@CHMSWZZXTNHC?==@EKQVYZXUOJD@>>AEKQVY[ZXTPLJIKNRVY[ZWRLFA>=>B778:>CHNRUUTPKE@=;;>BHMRUVTQLGB><<>CHMRUWVTPLIGGHKOSUVVSOID?<;CHLOPNKGB>:88;>CHLOPPNKHECCDFJMOPPMID?;878;))+.27BFHIHEA=96446:>BFHJIGEB?>>?ADGIIÂGC?:64347"#$'+059=?@?<952/..037;>@A@>:731//147;>@AA@=;9878:=?AAí?<841/./1!$(-1466×41.+)((*,/2578752/,*))*-035788753100134688È630-*)()+!%(+-.-+)'$#""#%(*-./.,*(%$##$&(+-.//.-+*))ü+,.//ú-+)&$""î$!#$%$#! ë #$%&%$" !#$&&õ%$#"!!"#$%&&ú%#!î óû÷úõ õûûî ü  û õ û  ó                õ ü 9 þ,  ú   ô û üþþ     ù ÷  þ  ù ÷ üþö õ ú  é ö  õ ùõ%%û$#"!  ü!""##ö"   óë !"#//õ.,+*)(()*+,,ç+)&# !"#$%%ù$#!ô"$')+,,899õ875321122455Ç42/+'" "$%&'()*+,--,+*(&#"!!"$'*.13566BCDCCA?=;::ü;<=>>å<84/*&" "%')*+,-./012344Ê20.,*))*-037;=?@@JLMMLKIFDBAABCEFGFDA=83.)&%%&(*,.01122Ã34689;<<;975321358=AEGIJJQSUVUTQNLIHGHIKMNNLJE@;61.,,-/2456766è5679<>ABCCB@><::;>AFJNQSSÚVY[\\[XUROMLLMORSTSQMHC>964468:;==<;988‰9;>BEHJKJIGECBCFINRVY[[ZZ]`bba^ZVRPNNPRUWYYWTOJEA><=>@ACCB@>;9889;?CHLOQQPOMKJKMQUY]`aa_[_cefeb^YUQOOQSWZ\]\ZVQLHFDEFGII€ùGD@=9778;?DIOSVWWVTRQRTW[_cefebZ_dghgd`ZUQONPSV[^``^[WSOMLLMOPONKGB=86458=CIPUZ\]\ZYWWY\_cghigdY^cghhe`ZUPMLNQUZ^acb_\XUSRSTUVURNIC=74236;AIPW\`aa`^\\]`cfikjhdW]bfhhe`ZTOKJLOTY_bdec`][YXYZ[[ZVQJC<61/028?GOW^bdedb``acehklkhcT[`eggd_XRMIHIMRX^cfgfda_^^€=`a`^ZTLD<50--055.*(*.5>HQZaeggfeddegijjhc]LSZ_bb_ZSLFA@AFLS[bgijjhggÂijkkid]TJ@70+)+/5>GPX_ceedcbbdfhiigb\LSY_bb_YSLEA@AELS[afijihffåhijjid^ULB92-+,/5=FNV\`bba``Ãbdghhfb\KRY^aa^YRKEA?AEKSZafhihfeddeghigd^VMD<50-.16=EMTY]^^]]…^`ceggea[KRY^aa^YRKEA@AEKSZ`eghfdbaabdefeb^WOF>830037=DKQVXZYYXYZ]`cefd`ZKQX]``]XRKEA@AEKRY_dffdb_^]^_abb`\WPHA:63358>CINRTTÂUWZ]addc_ZJQW\__\WQKEA@AEJQX^bcca^[YXYZ\]^]ZUOIC=86569=BGJMNONNÃPRVZ^aba^XIOUZ]]ZVPJDA?@DIPV[_``]ZWTSRSUWXXVSNIC>:878:=@DFHIHHÛJMRV[^_^[WGMRWYYWSMHB?>?BGMSX[\[XUQNLLìNPQRQOLGC?;9889;>@ABBAÂBDHLQVY[ZXSDJOSUUSOJE@=<=@DJOSVWVSOKHEDEFHIKKJGDA>;97789:;<<;::Ê<>BGLPTVVSO@EIMOOMJE@<989<@EIMPPOLHD@><<=?ABCCB@>;976556ý5433’57;@EJMOOMJ;?CGHIGD@;85457;?CFHIGDA=9654568:;<;:9754221100/.-,+,.049>BFHHFC48?@><-14677641.+*))+.13677530,)&%$$%'(*+,,Ú+*)('&%$"!  "&*.256764&)+-./.,)'%##é$&)+-..,*(%" "#$%%â$#"! #&),-.-+!#$%%¢#" !#$%%$" !#$%$#ä ûýú  û î ú û   þù û   ð  ü      þ  ú ô üþ   ! ˜ ˜ ˜×*   þþ    ù÷÷ ú     öö ù ô ì ñ þ#$$%ì$" ñ -.Ù-,)&"  678ö753/+'"ø!#$%&&ï%$#! @?ê@AA@?<84/*%" !#%(*,--í,+*(&# ýIHGGþHIIÙGEA<71,)&%&'*-/1344321/-*'# ýQPNNÖOPPOMJE?94/-,,.1479:;::8641.*&! æWUSRRSTUVVTQLF@;632247;>@AAì?=;851-(# ü\YVUUÖWYZ[ZWRMGA<978:=ADFHHGEB?<840*% Ð_[XVUVX[]^^\XRLFA><=?BFJLNNMKHD@<72,'! Ð_[WUTUX[^`a_\VPJEB@ACGKNQSSRPMID@:5/(" Ð_ZVSRSVZ^aba^YTMHDCCFINRUWXWURNID>81*$ Ï^XSPOQTX]acc`\VPJFDEGKPTXZ\[YWSNHB<4-& Ï\VQNMNRV\`cca]WQKGEEGKPUY\^^][WSMG@91)" ÏZTNKJKOTZ_bcb^XRLGEDFJOTY]`aa_\XSLE=5-% ÏYRLIGIMSY^bcb^XRLGDCDHMRW\_bcb`\XRKC:1)  ÎWPJGFGLQX^bcb^XRKFBABEJOUZ^acdc`\WPH?6-$ ÎVOIEDFJPW]acb^XQKEA?@BFKQV[_bddc`[UMD;1( ÎUNHDCEJPV]acb^XQJD@==?CGMRW\`bdcb^XQH?5+" ÎUNHDCEIPV\acb^XQJD?<;;:;=@EINSX\_aa_[UMD:0& ÎTMGDCEIOV\`bb^XQJD>;99;>AEJNSW[]^]ZUNE;1( ÎSMGDCEIOU[`ba^XQJD>;98:<>BFJNRVYZZXSMD;1( ÎRLGCCDINUZ_a`]WQJD>;989::8789:@CFIJJIE@:2*" ÎJEA?>?CHMRUWVSOJD?;75445678:<>@BCCB?:4-& êEA=;:BFHJIGC?;630/..è/0123455430,'" ê95311247;>@AA?<840.+*))*+ë,--..-+)%! ë1.,**+-025787630-*'%$$%&î'&%$! ü)'%$$ð&(*-./.-+(&#! ð é! !"$%&%$#!ñ üñò õøó þ  ù ù    ô þ       û  þ  øz=,d Backgroundÿ     ÿÿÿÿR\,dR|StS€SŒ,dR°RÎRÞRîRþSS4SDSTSdÿÿÿùÿûúôÿþÿ:ÿý Åÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ&ÿüþýüÿ>ÿýþýÿ>ÿüþÿüÿQÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ0ÿ0ÿ0ÿ0ÿ–2K% commons-jexl-2.1.1-src/src/site/site.xml100644 0 0 3624 11673634325 15302 0ustar 0 0 Commons JEXL images/jexl-logo-white.png index.html commons-jexl-2.1.1-src/src/site/xdoc/building.xml100644 0 0 3203 11673634326 17062 0ustar 0 0 Building Commons JEXL Commons Documentation Team

Commons JEXL uses Maven 2.2. The source is here.

The following goals are available.
  • mvn clean - clean up
  • mvn test - compile and run the unit tests
  • mvn site - create the documentation
  • mvn package - build the jar
  • mvn install - build the jar and install in local maven repository
commons-jexl-2.1.1-src/src/site/xdoc/changes.xml100644 0 0 24151 11673634326 16722 0ustar 0 0 Changes Commons Developers Array parameters to methods don't work anymore (regression) Add simple template features Make ParseException work in sandboxed environment Allow indexed properties container resolution in expressions Provide an IN operator: =~ / match operator extended to provide IN behavior (!~ as NOT IN) Add control over classes, methods, constructors and properties allowed in scripts Add support for asynchronous script execution and cancellation Allow scripts to create local variables // Add return keyword Add functions to extract which variables, parameters and local variables are used to evaluate a script Cannot parse Integer.MIN_VALUE. Support Long for integer literal instead of Integers. Added ObjectContext that wraps an object as JexlContext and added JexlContext as source to solve top-level namespace functions. expression execute error depending on numeric type Make JexlArithmetic immutable (and threadsafe); also added a mutable JexlThreadedArithmetic. Parsing error if i define a empty literal array/map Literals and parenthesized expressions can not be used as references When divide two BigDecimal values in an expression it results in java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. Array literals are considered constant even when they are not. NPE in JexlArithmetic when an Array-Expression containing a null is used. Add "jexl2" as a supported name Vararg methods where the first argument is no vararg can not be called with only the fixed parameters given Array access expressions fail when evaluated twice and cache is enabled Documentation of Thread Safety / Invalid code examples on homepage Quote escaping cannot be escaped Bean-ish & ant-ish like assignment Ternary operator support adding Perl-like regular-expression operators Support for ${...} and #{...} expressions User definable functions JSR-223 support Make possible checking for unresolved variables Don"t make null convertible into anything Allow single-line comments with // Comments don"t allow double-quotes Array literal syntax is not supported allowing quote escaping Call method with varargs BigDecimal values are treated as Long values which results in loss of precision Remove unnecessary throws Exception from various classes Div operator does not do integer division Inconsistent behaviour of arithmetical operations operator overloading / hooks on operator processing "new" operator support Support Unicode escapes in string literals Various performance enhancements & caches Fix jdk1.3 only code that has crept into Jexl tests Allow unicode literals to be used Consistently throw ParseException in case of a parsing failure, not an Error. Allow for static methods to be called on classes and not just objects. Added Script and ScriptFactory to allow scripts to be executed from text, files or a URL. Added implementation for bitwise operators: and, complement, or, xor. Added implementation for the foreach statement. Added implementation for the while statement. Added implementation for block statements, e.g. curly braces containing multiple statements. Added implementation for the if statement. Unary minus was only working for integer values. Add @since tags to code so we can track API additions via javadoc Support assignment to variables 'abc'.substring(0,1+1) is empty (method matching problem) Support ant-style properties Fix string concatenation broken for variables Implement short circuit logic for boolean and/or Handle any size() method that returns an int Can't issue .size() on java.util.Set commons-jexl-2.1.1-src/src/site/xdoc/download_jexl.xml100644 0 0 21146 11673634326 20144 0ustar 0 0 Download Commons JEXL Commons Documentation Team

We recommend you use a mirror to download our release builds, but you must verify the integrity of the downloaded files using signatures downloaded from our main distribution directories. Recent releases (48 hours) may not yet be available from the mirrors.

You are currently using [preferred]. If you encounter a problem with this mirror, please select another mirror. If all mirrors are failing, there are backup mirrors (at the end of the mirrors list) that should be available.

[if-any logo][end]

Other mirrors:

The KEYS link links to the code signing keys used to sign the product. The PGP link downloads the OpenPGP compatible signature from our main site. The MD5 link downloads the checksum from the main site.

commons-jexl-2.1.1-bin.tar.gz md5 pgp
commons-jexl-2.1.1-bin.zip md5 pgp
commons-jexl-2.1.1-src.tar.gz md5 pgp
commons-jexl-2.1.1-src.zip md5 pgp
commons-jexl-1.1.tar.gz md5 pgp
commons-jexl-1.1.zip md5 pgp
commons-jexl-1.1-src.tar.gz md5 pgp
commons-jexl-1.1-src.zip md5 pgp

Older releases can be obtained from the archives.

commons-jexl-2.1.1-src/src/site/xdoc/index.xml100644 0 0 24645 11673634326 16431 0ustar 0 0 Commons JEXL Overview

JEXL is a library intended to facilitate the implementation of dynamic and scripting features in applications and frameworks written in Java.

JEXL implements an Expression Language based on some extensions to the JSTL Expression Language supporting most of the constructs seen in shell-script or ECMAScript.
Its goal is to expose scripting features usable by technical operatives or consultants working with enterprise platforms.

The library exposes a small footprint API - the core features fit in 3 classes and 10 methods - that can be used in various conditions:

  • Scripting features:
    • Your application lets (advanced) users evaluate or define some simple expressions like computation formulas.
  • Module or component configuration:
    • Your application has configuration files (eventually generated by a design module) consumed by the end-user module that would benefit from variables and expressions.
    • When it would be convenient to use IOC but overall complexity doesn't require (or can't depend upon) a full-blown library (Spring, Guice...).
  • Loose-coupling of interfaces and implementations or duck-typing:
    • You have optional classes that your code cant consider as compilation dependencies.
    • You have to integrate and call "legacy" code or use components that you dont want to strongly depend upon.
  • Simple template capabilities:
    • Your application has basic template requirements and JSPs or Velocity would be overkill or too inconvenient to deploy.

JEXL name stands for Java EXpression Language, a simple expression language originally inspired by Apache Velocity and the Expression Language defined in the JavaServer Pages Standard Tag Library version 1.1 (JSTL) and JavaServer Pages version 2.0 (JSP). JEXL 2.0 added features inspired by Unified EL. The syntax is now close to a mix of ECMAScript and "shell-script" making it easy to master by technical operatives or consultants. The objects exposed and their behavior obviously need to be documented though...

The API and the expression language exploit Java-beans naming patterns through introspection to expose property getters and setters. It also considers public class fields as properties and allows to invoke any accessible method.

JEXL attempts to bring some of the lessons learned by the Velocity community about expression languages in templating to a wider audience. Commons Jelly needed Velocity-ish method access, it just had to have it.

It must be noted that JEXL is not a compatible implementation of EL as defined in JSTL 1.1 (JSR-052) or JSP 2.0 (JSR-152). For a compatible implementation of these specifications, see the Commons EL project.

When evaluating expressions, JEXL merges an Expression with a JexlContext. An Expression is created using JexlEngine#createExpression(), passing a String containing valid JEXL syntax. A simple JexlContext can be created by instantiating a MapContext; a map of variables that will be internally wrapped can be optionally provided through its constructor. The following example, takes a variable named foo, and invokes the bar() method on the property innerFoo:

While JEXL is similar to the expression language defined in JSTL, it has improved upon the syntax in a few areas:

  • Support for invocation of any accessible method (see example above).
  • Support for setting/getting any accessible public field.
  • A general size() method, which works on:
    • String - returns length
    • Map - returns number of keys
    • List - returns number of elements.
  • A general empty() method, which works on Collections and Strings.
  • A general new() method allowing to instantiate objects.
  • Support for the ternary operator 'a ? b : c' - and its GNU-C / "Elvis" variant 'a ?: c'.
  • Support for the Perl-like regex matching operators '=~' and '!~'
  • Misc : '+' has been overloaded to be use as a String concatenation operator

JEXL is not a product of the Java Community Process (JCP), but it provides a similar expression syntax. For more information about JSP 2.0 EL and JSTL 1.1 EL:

Apache Velocity implements a similar expression language.

In particular the References section of the User Guide has some good information on properties and method which correlate directly to JEXL.

commons-jexl-2.1.1-src/src/site/xdoc/issue-tracking.xml100644 0 0 13367 11673634326 20251 0ustar 0 0 Commons JEXL Issue tracking Commons Documentation Team

Commons JEXL uses ASF JIRA for tracking issues. See the Commons JEXL JIRA project page.

To use JIRA you may need to create an account (if you have previously created/updated Commons issues using Bugzilla an account will have been automatically created and you can use the Forgot Password page to get a new password).

If you would like to report a bug, or raise an enhancement request with Commons JEXL please do the following:

  1. Search existing open bugs. If you find your issue listed then please add a comment with your details.
  2. Search the mailing list archive(s). You may find your issue or idea has already been discussed.
  3. Decide if your issue is a bug or an enhancement.
  4. Submit either a bug report or enhancement request.

Please also remember these points:

  • the more information you provide, the better we can help you
  • test cases are vital, particularly for any proposed enhancements
  • the developers of Commons JEXL are all unpaid volunteers

For more information on subversion and creating patches see the Apache Contributors Guide.

You may also find these links useful:

commons-jexl-2.1.1-src/src/site/xdoc/mail-lists.xml100644 0 0 22536 11673634326 17375 0ustar 0 0 Commons JEXL Mailing Lists Commons Documentation Team

Commons JEXL shares mailing lists with all the other Commons Components. To make it easier for people to only read messages related to components they are interested in, the convention in Commons is to prefix the subject line of messages with the component's name, for example:

  • [jexl] Problem with the ...

Questions related to the usage of Commons JEXL should be posted to the User List.
The Developer List is for questions and discussion related to the development of Commons JEXL.
Please do not cross-post; developers are also subscribed to the user list.

Note: please don't send patches or attachments to any of the mailing lists. Patches are best handled via the Issue Tracking system. Otherwise, please upload the file to a public server and include the URL in the mail.

Please prefix the subject line of any messages for Commons JEXL with [jexl] - thanks!

Name Subscribe Unsubscribe Post Archive Other Archives
Commons User List

Questions on using Commons JEXL.

Subscribe Unsubscribe Post mail-archives.apache.org markmail.org
www.mail-archive.com
news.gmane.org
Commons Developer List

Discussion of development of Commons JEXL.

Subscribe Unsubscribe Post mail-archives.apache.org markmail.org
www.mail-archive.com
news.gmane.org
Commons Issues List

Only for e-mails automatically generated by the issue tracking system.

Subscribe Unsubscribe read only mail-archives.apache.org markmail.org
www.mail-archive.com
Commons Commits List

Only for e-mails automatically generated by the source control sytem.

Subscribe Unsubscribe read only mail-archives.apache.org markmail.org
www.mail-archive.com

Other mailing lists which you may find useful include:

Name Subscribe Unsubscribe Post Archive Other Archives
Apache Announce List

General announcements of Apache project releases.

Subscribe Unsubscribe read only mail-archives.apache.org markmail.org
old.nabble.com
www.mail-archive.com
news.gmane.org
commons-jexl-2.1.1-src/src/site/xdoc/reference/examples.xml100644 0 0 22372 11673634326 21071 0ustar 0 0 Commons JEXL Examples

In this reference you will find the following topics to help with your use of JEXL.

You can find two sample programs in JEXL's CVS repository:

As well, JEXL's Unit Tests provide handy examples of expressions. The test code also contains a simple class that evaluates its command line arguments as JEXL expressions when run.

The package javadoc also contains useful information.

To evaluate expressions using JEXL, you need three things:

The common way of using a JEXL engine is to allocate it as a singleton and use this opportunity to tailor its behavior and cache. private static final JexlEngine jexl = new JexlEngine(); static { jexl.setCache(512); jexl.setLenient(false); jexl.setSilent(false); }

The easiest way of obtaining a a context is to use the new MapContext() statement. This creates a context implemented using an underlying HashMap

Expressions are created using the JexlEngine.createExpression(String) method.

Once you have your expression, you can then use use the evaluate to execute it and obtain a result.

Here's a typical scenario:

// Assuming we have a JexlEngine instance initialized in our class named 'jexl': // Create an expression object for our calculation String calculateTax = taxManager.getTaxCalc(); //e.g. "((G1 + G2 + G3) * 0.1) + G4"; Expression e = jexl.createExpression( calculateTax ); // populate the context JexlContext context = new MapContext(); context.set("G1", businessObject.getTotalSales()); context.set("G2", taxManager.getTaxCredit(businessObject.getYear())); context.set("G3", businessObject.getIntercompanyPayments()); context.set("G4", -taxManager.getAllowances()); // ... // work it out Float result = (Float)e.evaluate(context);

Often you have the objects and values that are needed in the context available elsewhere. If those are already in a Map, instead of creating the default context and populating it manually in the code, you can wrap a MapContext around your own map using new MapContext(yourOwnMap)

In edge cases, it may be simpler to create a context implementation of your own. The JexlContext interface is very simple with only three methods, to set, get and check the existence of variables.

Most valid arithmetic expressions in Java are also valid in Jexl.

1 + 2 12.0 - 5.2 6 * 12 + 5 / 2.6 12 % 2 6 / 4 -12 + 77.2 x * 1.1 + y

Arithmetic expressions can use variables. null can be treated as a zero for arithmetic; if you need stricter semantics and consider null as an erroneous operand for arithmetic and comparisons operations, you should initialize your JEXL engine using JexlEngine.setLenient(false).

JEXL allows you to call any method on a Java object using the same syntax. If you have a string in the context under the name aString, you could call it's length method like this: aString.length() aString.substring(6)

Often the values you want to pass to a method are other variables or expressions. If you have a number in the context, named i, you could use it in a method call: aString.substring(i)

JEXL provides a shorthand syntax to access methods that follow the JavaBean naming convention for properties, i.e. setters and getters.

If you have some object foo in the context and it has a method getBar(), you can call that method using the following syntax: foo.bar

Since java.lang.Object has a getClass() method that returns a java.lang.Class object, and the class has a getName() method, the following is a shorthand for obtaining the class name of an object foo in the context: foo.class.name

Array elements can be accessed using either square brackets or a dotted index notation, e.g. the following are equivalent arr[0] arr.0 The same holds true for lists.

For a map, the syntax is very similar, except the 'index' is an object, e.g. the following are equivalent. aMap['key'] aMap.get('key') Please note that the index does not have to be a string, and that the string usage above is just one possible option.

commons-jexl-2.1.1-src/src/site/xdoc/reference/index.xml100644 0 0 2601 11673634326 20333 0ustar 0 0 Commons JEXL Reference

The JEXL Reference documentation is made up of the following:

commons-jexl-2.1.1-src/src/site/xdoc/reference/jsr223.xml100644 0 0 7554 11673634326 20265 0ustar 0 0 Commons JEXL JSR-223 (scripting) Reference

Commons JEXL includes JSR-223 (javax.script) support. The binary jar includes the scripting factory and the services definition javax.script.ScriptEngineFactory, so no special configuration is needed.

The provided script engine implements the following (engineVersion="1.0"):

  • Language names: "JEXL", "Jexl", "jexl"
  • Extensions: ".jexl"
  • Mime-types: "application/x-jexl"
Script Engine versions from "2.0" also implement the following:
  • Language names: "JEXL2", "Jexl2", "jexl2"
  • Extensions: ".jexl2"
  • Mime-types: "application/x-jexl2"
The implementation adds an instance of JexlScriptObject to the engine context as the variable "JEXL". This gives scripts easier access to various items such as System.out and a logger.

The binary release includes a command-line application which can be used to exercise the JSR-223 script engine. For example: java -cp commons-jexl-2.0.1.jar;commons-logging-1.1.1.jar[;bsf-api-3.0.jar] org.apache.commons.jexl2.scripting.Main script.jexl If a single argument is provided, then that is assumed to be the name of a script file; otherwise, the application prompts for script input to be evaluated. In both cases, the variable "args" contains the command-line arguments. [Note that Java 1.5 does not include javax.script support; you will need to use the Apache BSF API jar as indicated.]

In order to use JEXL via JSR-223 on Java 1.5, you need to add Apache BSF-API 3.0 jar to the classpath. JEXL also requires Commons Logging on the classpath.

JSR-223 support is included with Java 1.6+. JEXL requires Commons Logging, which needs to be included in the path.

The classes used to support JSR-223 scripting access are:

  • org.apache.commons.jexl2.scripting.JexlScriptEngineFactory - the factory
  • org.apache.commons.jexl2.scripting.JexlScriptEngine - the engine
  • org.apache.commons.jexl2.scripting.JexlScriptObject - class used to give scripts access to JEXL objects

commons-jexl-2.1.1-src/src/site/xdoc/reference/syntax.xml100644 0 0 57520 11673634326 20604 0ustar 0 0 Commons JEXL Syntax

This reference is split up into the following sections:

  1. Language Elements
  2. Literals
  3. Functions
  4. Operators
  5. Conditional Statements

For more technical information about the JEXL Grammar, you can find the JavaCC grammar for JEXL here: Parser.jjt

ItemDescription
Comments Specified using ## or //and extend to the end of line, e.g. ## This is a comment Also specified using //, e.g. // This is a comment Multiple lines comments are specified using /*...*/, e.g. /* This is a multi-line comment */
Identifiers / variables Must start with a-z, A-Z, _ or $. Can then be followed by 0-9, a-z, A-Z, _ or $. e.g.
  • Valid: var1,_a99,$1
  • Invalid: 9v,!a99,1$

Variable names are case-sensitive, e.g. var1 and Var1 are different variables.

NOTE: JEXL does not support variables with hyphens in them, e.g. commons-logging // invalid variable name (hyphenated) is not a valid variable, but instead is treated as a subtraction of the variable logging from the variable commons

JEXL also supports ant-style variables, the following is a valid variable name: my.dotted.var

N.B. the following keywords are reserved, and cannot be used as a variable name or property when using the dot operator: or and eq ne lt gt le ge div mod not null true false new var return For example, the following is invalid: my.new.dotted.var // invalid ('new' is keyword) In such cases, quoted identifiers or the [ ] operator can be used, for example: my.'new'.dotted.var my['new'].dotted.var

Scripts

A script in Jexl is made up of zero or more statements. Scripts can be read from a String, File or URL.

They can be created with named parameters which allow a later evaluation to be performed with arguments.

A script returns the last expression evaluated by default.

Using the return keyword, a script will return the expression that follows (or null).

Local variables Can be defined using the var keyword; their identifying rules are the same as contextual variables.
  • Basic declaration: var x;
  • Declaration with assignment: var theAnswer = 42;
  • Invalid declaration: var x.y;
Their scope is the entire script scope and they take precedence in resolution over contextual variables. When scripts are created with named parameters, those behave as local variables. Local variables can not use ant-style naming, only one identifier.
Statements A statement can be the empty statement, the semicolon (;) , block, assignment or an expression. Statements are optionally terminated with a semicolon.
Block A block is simply multiple statements inside curly braces ({, }).
Assignment Assigns the value of a variable (my.var = 'a value') using a JexlContext as initial resolver. Both beans and ant-ish variables assignment are supported.
Method calls Calls a method of an object, e.g. "hello world".hashCode() will call the hashCode method of the "hello world" String.

In case of multiple arguments and overloading, Jexl will make the best effort to find the most appropriate non ambiguous method to call.

ItemDescription
Integer Literals 1 or more digits from 0 to 9, eg 42.
Float Literals 1 or more digits from 0 to 9, followed by a decimal point and then one or more digits from 0 to 9, optionally followed by f or F, eg 42.0 or 42.0f.
Long Literals 1 or more digits from 0 to 9 suffixed with l or L , eg 42l.
Double Literals 1 or more digits from 0 to 9, followed by a decimal point and then one or more digits from 0 to 9 suffixed with d or D , eg 42.0d.
Big Integer Literals 1 or more digits from 0 to 9 suffixed with b or B , eg 42B.
Big Decimal Literals 1 or more digits from 0 to 9, followed by a decimal point and then one or more digits from 0 to 9 suffixed with h or H (for Huge ala OGNL)) , eg 42.0H.
Natural literals - octal and hex support Natural numbers (i.e. Integer, Long, BigInteger) can also be expressed as octal or hexadecimal using the same format as Java. i.e. prefix the number with 0 for octal, and prefix with 0x or 0X for hexadecimal. For example 010 or 0x10.
Real literals - exponent support Real numbers (i.e. Float, Double, BigDecimal) can also be expressed using standard Java exponent notation. i.e. suffix the number with e or E followed by the sign + or - followed by one or more decimal digits. For example 42.0E-1D or 42.0E+3B.
String literals Can start and end with either ' or " delimiters, e.g. "Hello world" and 'Hello world' are equivalent.

The escape character is \ (backslash); it only escapes the string delimiter

Boolean literals The literals true and false can be used, e.g. val1 == true
Null literal The null value is represented as in java using the literal null, e.g. val1 == null
Array literal A [ followed by one or more expressions separated by , and ending with ], e.g. [ 1, 2, "three" ]

This syntax creates an Object[].

JEXL will attempt to strongly type the array; if all entries are of the same class or if all entries are Number instance, the array literal will be an MyClass[] in the former case, a Number[] in the latter case.

Furthermore, if all entries in the array literal are of the same class and that class has an equivalent primitive type, the array returned will be a primitive array. e.g. [1, 2, 3] will be interpreted as int[].

Map literal A { followed by one or more sets of key : value pairs separated by , and ending with }, e.g. { "one" : 1, "two" : 2, "three" : 3, "more": "many more" }

This syntax creates a HashMap<Object,Object>.

FunctionDescription
empty Returns true if the expression following is either:
  1. null
  2. An empty string
  3. An array of length zero
  4. A collection of size zero
  5. An empty map
empty(var1)
size Returns the information about the expression:
  1. Length of an array
  2. Size of a List
  3. Size of a Map
  4. Size of a Set
  5. Length of a string
size("Hello") returns 5.
new Creates a new instance using a fully-qualified class name or Class: new("java.lang.Double", 10) returns 10.0.

Note that the first argument of new can be a variable or any expression evaluating as a String or Class; the rest of the arguments are used as arguments to the constructor for the class considered.

In case of multiple constructors, Jexl will make the best effort to find the most appropriate non ambiguous constructor to call.

ns:function A JexlEngine can register objects or classes used as function namespaces. This can allow expressions like: math:cosinus(23.0)
OperatorDescription
Boolean and The usual && operator can be used as well as the word and, e.g. cond1 and cond2 and cond1 && cond2 are equivalent
Boolean or The usual || operator can be used as well as the word or, e.g. cond1 or cond2 and cond1 || cond2 are equivalent
Boolean not The usual ! operator can be used as well as the word not, e.g. !cond1 and not cond1 are equivalent
Bitwise and The usual & operator is used, e.g. 33 & 4, 0010 0001 & 0000 0100 = 0.
Bitwise or The usual | operator is used, e.g. 33 | 4, 0010 0001 | 0000 0100 = 0010 0101 = 37.
Bitwise xor The usual ^ operator is used, e.g. 33 ^ 4, 0010 0001 ^ 0000 0100 = 0010 0100 = 37.
Bitwise complement The usual ~ operator is used, e.g. ~33, ~0010 0001 = 1101 1110 = -34.
Ternary conditional ?: The usual ternary conditional operator condition ? if_true : if_false operator can be used as well as the abbreviation value ?: if_false which returns the value if its evaluation is defined, non-null and non-false, e.g. val1 ? val1 : val2 and val1 ?: val2 are equivalent.

NOTE: The condition will evaluate to false when it refers to an undefined variable or null for all JexlEngine flag combinations. This allows explicit syntactic leniency and treats the condition 'if undefined or null or false' the same way in all cases.

Equality The usual == operator can be used as well as the abbreviation eq. For example val1 == val2 and val1 eq val2 are equivalent.
  1. null is only ever equal to null, that is if you compare null to any non-null value, the result is false.
  2. Equality uses the java equals method
Inequality The usual != operator can be used as well as the abbreviation ne. For example val1 != val2 and val1 ne val2 are equivalent.
Less Than The usual < operator can be used as well as the abbreviation lt. For example val1 < val2 and val1 lt val2 are equivalent.
Less Than Or Equal To The usual <= operator can be used as well as the abbreviation le. For example val1 <= val2 and val1 le val2 are equivalent.
Greater Than The usual > operator can be used as well as the abbreviation gt. For example val1 > val2 and val1 gt val2 are equivalent.
Greater Than Or Equal To The usual >= operator can be used as well as the abbreviation ge. For example val1 >= val2 and val1 ge val2 are equivalent.
In or Match=~ The syntactically Perl inspired =~ operator can be used to check that a string matches a regular expression (expressed either a Java String or a java.util.regex.Pattern). For example "abcdef" =~ "abc.* returns true. It also checks whether any collection, set or map (on keys) contains a value or not; in that case, it behaves as an "in" operator. Note that it also applies to arrays as well as "duck-typed" collection, ie classes exposing a "contains" method. "a" =~ ["a","b","c","d","e",f"] returns true.
Not-In or Not-Match!~ The syntactically Perl inspired !~ operator can be used to check that a string does not match a regular expression (expressed either a Java String or a java.util.regex.Pattern). For example "abcdef" !~ "abc.* returns false. It also checks whether any collection, set or map (on keys) does not contain a value; in that case, it behaves as "not in" operator. Note that it also applies to arrays as well as "duck-typed" collection, ie classes exposing a "contains" method. "a" !~ ["a","b","c","d","e",f"] returns true.
Addition The usual + operator is used. For example val1 + val2
Subtraction The usual - operator is used. For example val1 - val2
Multiplication The usual * operator is used. For example val1 * val2
Division The usual / operator is used, or one can use the div operator. For example val1 / val2 or val1 div val2
Modulus (or remainder) The % operator is used. An alternative is the mod operator. For example 5 mod 2 gives 1 and is equivalent to 5 % 2
Negation The unary - operator is used. For example -12
Array access Array elements may be accessed using either square brackets or a dotted numeral, e.g. arr1[0] and arr1.0 are equivalent
HashMap access Map elements are accessed using square brackets, e.g. map[0]; map['name']; map[var]; Note that map['7'] and map[7] refer to different elements. Map elements with a numeric key may also be accessed using a dotted numeral, e.g. map[0] and map.0 are equivalent.
OperatorDescription
if Classic, if/else statement, e.g. if ((x * 2) == 5) { y = 1; } else { y = 2; }
for Loop through items of an Array, Collection, Map, Iterator or Enumeration, e.g. for(item : list) { x = x + item; } Where item and list are variables. The JEXL 1.1 syntax using foreach(item in list) is now deprecated.
while Loop until a condition is satisfied, e.g. while (x lt 10) { x = x + 2; }
commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/ArithmeticTest.java100644 0 0 35345 11673634320 25073 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.Map; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.jexl2.junit.Asserter; public class ArithmeticTest extends JexlTestCase { private Asserter asserter; public ArithmeticTest() { super(createThreadedArithmeticEngine(true)); } @Override public void setUp() { asserter = new Asserter(JEXL); } public void testUndefinedVar() throws Exception { asserter.failExpression("objects[1].status", ".* undefined variable objects.*"); } public void testLeftNullOperand() throws Exception { asserter.setVariable("left", null); asserter.setVariable("right", Integer.valueOf(8)); asserter.failExpression("left + right", ".*null.*"); asserter.failExpression("left - right", ".*null.*"); asserter.failExpression("left * right", ".*null.*"); asserter.failExpression("left / right", ".*null.*"); asserter.failExpression("left % right", ".*null.*"); asserter.failExpression("left & right", ".*null.*"); asserter.failExpression("left | right", ".*null.*"); asserter.failExpression("left ^ right", ".*null.*"); } public void testRightNullOperand() throws Exception { asserter.setVariable("left", Integer.valueOf(9)); asserter.setVariable("right", null); asserter.failExpression("left + right", ".*null.*"); asserter.failExpression("left - right", ".*null.*"); asserter.failExpression("left * right", ".*null.*"); asserter.failExpression("left / right", ".*null.*"); asserter.failExpression("left % right", ".*null.*"); asserter.failExpression("left & right", ".*null.*"); asserter.failExpression("left | right", ".*null.*"); asserter.failExpression("left ^ right", ".*null.*"); } public void testNullOperands() throws Exception { asserter.setVariable("left", null); asserter.setVariable("right", null); asserter.failExpression("left + right", ".*null.*"); asserter.failExpression("left - right", ".*null.*"); asserter.failExpression("left * right", ".*null.*"); asserter.failExpression("left / right", ".*null.*"); asserter.failExpression("left % right", ".*null.*"); asserter.failExpression("left & right", ".*null.*"); asserter.failExpression("left | right", ".*null.*"); asserter.failExpression("left ^ right", ".*null.*"); } public void testNullOperand() throws Exception { asserter.setVariable("right", null); asserter.failExpression("~right", ".*null.*"); asserter.failExpression("-right", ".*arithmetic.*"); } public void testBigDecimal() throws Exception { asserter.setVariable("left", new BigDecimal(2)); asserter.setVariable("right", new BigDecimal(6)); asserter.assertExpression("left + right", new BigDecimal(8)); asserter.assertExpression("right - left", new BigDecimal(4)); asserter.assertExpression("right * left", new BigDecimal(12)); asserter.assertExpression("right / left", new BigDecimal(3)); asserter.assertExpression("right % left", new BigDecimal(0)); } public void testBigInteger() throws Exception { asserter.setVariable("left", new BigInteger("2")); asserter.setVariable("right", new BigInteger("6")); asserter.assertExpression("left + right", new BigInteger("8")); asserter.assertExpression("right - left", new BigInteger("4")); asserter.assertExpression("right * left", new BigInteger("12")); asserter.assertExpression("right / left", new BigInteger("3")); asserter.assertExpression("right % left", new BigInteger("0")); } /** * test some simple mathematical calculations */ public void testUnaryMinus() throws Exception { asserter.setVariable("aByte", new Byte((byte) 1)); asserter.setVariable("aShort", new Short((short) 2)); asserter.setVariable("anInteger", new Integer(3)); asserter.setVariable("aLong", new Long(4)); asserter.setVariable("aFloat", new Float(5.5)); asserter.setVariable("aDouble", new Double(6.6)); asserter.setVariable("aBigInteger", new BigInteger("7")); asserter.setVariable("aBigDecimal", new BigDecimal("8.8")); asserter.assertExpression("-3", new Integer("-3")); asserter.assertExpression("-3.0", new Float("-3.0")); asserter.assertExpression("-aByte", new Byte((byte) -1)); asserter.assertExpression("-aShort", new Short((short) -2)); asserter.assertExpression("-anInteger", new Integer(-3)); asserter.assertExpression("-aLong", new Long(-4)); asserter.assertExpression("-aFloat", new Float(-5.5)); asserter.assertExpression("-aDouble", new Double(-6.6)); asserter.assertExpression("-aBigInteger", new BigInteger("-7")); asserter.assertExpression("-aBigDecimal", new BigDecimal("-8.8")); } /** * test some simple mathematical calculations */ public void testCalculations() throws Exception { asserter.setVariable("foo", new Integer(2)); asserter.assertExpression("foo + 2", new Integer(4)); asserter.assertExpression("3 + 3", new Integer(6)); asserter.assertExpression("3 + 3 + foo", new Integer(8)); asserter.assertExpression("3 * 3", new Integer(9)); asserter.assertExpression("3 * 3 + foo", new Integer(11)); asserter.assertExpression("3 * 3 - foo", new Integer(7)); /* * test parenthesized exprs */ asserter.assertExpression("(4 + 3) * 6", new Integer(42)); asserter.assertExpression("(8 - 2) * 7", new Integer(42)); /* * test some floaty stuff */ asserter.assertExpression("3 * \"3.0\"", new Double(9)); asserter.assertExpression("3 * 3.0", new Double(9)); /* * test / and % */ asserter.assertExpression("6 / 3", new Integer(6 / 3)); asserter.assertExpression("6.4 / 3", new Double(6.4 / 3)); asserter.assertExpression("0 / 3", new Integer(0 / 3)); asserter.assertExpression("3 / 0", new Double(0)); asserter.assertExpression("4 % 3", new Integer(1)); asserter.assertExpression("4.8 % 3", new Double(4.8 % 3)); /* * test new null coersion */ asserter.setVariable("imanull", null); asserter.assertExpression("imanull + 2", new Integer(2)); asserter.assertExpression("imanull + imanull", new Integer(0)); } public void testCoercions() throws Exception { asserter.assertExpression("1", new Integer(1)); // numerics default to Integer // asserter.assertExpression("5L", new Long(5)); // TODO when implemented asserter.setVariable("I2", new Integer(2)); asserter.setVariable("L2", new Long(2)); asserter.setVariable("L3", new Long(3)); asserter.setVariable("B10", BigInteger.TEN); // Integer & Integer => Integer asserter.assertExpression("I2 + 2", new Integer(4)); asserter.assertExpression("I2 * 2", new Integer(4)); asserter.assertExpression("I2 - 2", new Integer(0)); asserter.assertExpression("I2 / 2", new Integer(1)); // Integer & Long => Long asserter.assertExpression("I2 * L2", new Long(4)); asserter.assertExpression("I2 / L2", new Long(1)); // Long & Long => Long asserter.assertExpression("L2 + 3", new Long(5)); asserter.assertExpression("L2 + L3", new Long(5)); asserter.assertExpression("L2 / L2", new Long(1)); asserter.assertExpression("L2 / 2", new Long(1)); // BigInteger asserter.assertExpression("B10 / 10", BigInteger.ONE); asserter.assertExpression("B10 / I2", new BigInteger("5")); asserter.assertExpression("B10 / L2", new BigInteger("5")); } public static class MatchingContainer { private final Set values; public MatchingContainer(int[] is) { values = new HashSet(); for (int value : is) { values.add(value); } } public boolean contains(int value) { return values.contains(value); } } public void testRegexp() throws Exception { asserter.setVariable("str", "abc456"); asserter.assertExpression("str =~ '.*456'", Boolean.TRUE); asserter.assertExpression("str !~ 'ABC.*'", Boolean.TRUE); asserter.setVariable("match", "abc.*"); asserter.setVariable("nomatch", ".*123"); asserter.assertExpression("str =~ match", Boolean.TRUE); asserter.assertExpression("str !~ match", Boolean.FALSE); asserter.assertExpression("str !~ nomatch", Boolean.TRUE); asserter.assertExpression("str =~ nomatch", Boolean.FALSE); asserter.setVariable("match", java.util.regex.Pattern.compile("abc.*")); asserter.setVariable("nomatch", java.util.regex.Pattern.compile(".*123")); asserter.assertExpression("str =~ match", Boolean.TRUE); asserter.assertExpression("str !~ match", Boolean.FALSE); asserter.assertExpression("str !~ nomatch", Boolean.TRUE); asserter.assertExpression("str =~ nomatch", Boolean.FALSE); // check the in/not-in variant asserter.assertExpression("'a' =~ ['a','b','c','d','e','f']", Boolean.TRUE); asserter.assertExpression("'a' !~ ['a','b','c','d','e','f']", Boolean.FALSE); asserter.assertExpression("'z' =~ ['a','b','c','d','e','f']", Boolean.FALSE); asserter.assertExpression("'z' !~ ['a','b','c','d','e','f']", Boolean.TRUE); // check in/not-in on array, list, map, set and duck-type collection int[] ai = {2, 4, 42, 54}; List al = new ArrayList(); for(int i : ai) { al.add(i); } Map am = new HashMap(); am.put(2, "two"); am.put(4, "four"); am.put(42, "forty-two"); am.put(54, "fifty-four"); MatchingContainer ad = new MatchingContainer(ai); Set as = ad.values; Object[] vars = { ai, al, am, ad, as }; for(Object var : vars) { asserter.setVariable("container", var); for(int x : ai) { asserter.setVariable("x", x); asserter.assertExpression("x =~ container", Boolean.TRUE); } asserter.setVariable("x", 169); asserter.assertExpression("x !~ container", Boolean.TRUE); } } /** * * if silent, all arith exception return 0.0 * if not silent, all arith exception throw * @throws Exception */ public void testDivideByZero() throws Exception { Map vars = new HashMap(); JexlContext context = new MapContext(vars); vars.put("aByte", new Byte((byte) 1)); vars.put("aShort", new Short((short) 2)); vars.put("aInteger", new Integer(3)); vars.put("aLong", new Long(4)); vars.put("aFloat", new Float(5.5)); vars.put("aDouble", new Double(6.6)); vars.put("aBigInteger", new BigInteger("7")); vars.put("aBigDecimal", new BigDecimal("8.8")); vars.put("zByte", new Byte((byte) 0)); vars.put("zShort", new Short((short) 0)); vars.put("zInteger", new Integer(0)); vars.put("zLong", new Long(0)); vars.put("zFloat", new Float(0)); vars.put("zDouble", new Double(0)); vars.put("zBigInteger", new BigInteger("0")); vars.put("zBigDecimal", new BigDecimal("0")); String[] tnames = { "Byte", "Short", "Integer", "Long", "Float", "Double", "BigInteger", "BigDecimal" }; // number of permutations this will generate final int PERMS = tnames.length * tnames.length; JexlEngine jexl = createThreadedArithmeticEngine(true); jexl.setCache(128); jexl.setSilent(false); // for non-silent, silent... for (int s = 0; s < 2; ++s) { JexlThreadedArithmetic.setLenient(Boolean.valueOf(s == 0)); int zthrow = 0; int zeval = 0; // for vars of all types... for (String vname : tnames) { // for zeros of all types... for (String zname : tnames) { // divide var by zero String expr = "a" + vname + " / " + "z" + zname; try { Expression zexpr = jexl.createExpression(expr); Object nan = zexpr.evaluate(context); // check we have a zero & incremement zero count if (nan instanceof Number) { double zero = ((Number) nan).doubleValue(); if (zero == 0.0) { zeval += 1; } } } catch (Exception any) { // increment the exception count zthrow += 1; } } } if (!jexl.isLenient()) { assertTrue("All expressions should have thrown " + zthrow + "/" + PERMS, zthrow == PERMS); } else { assertTrue("All expressions should have zeroed " + zeval + "/" + PERMS, zeval == PERMS); } } debuggerCheck(jexl); } }commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/ArrayAccessTest.java100644 0 0 21302 11673634317 25174 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.jexl2.junit.Asserter; /** * Tests for array access operator [] * * @since 2.0 */ public class ArrayAccessTest extends JexlTestCase { private Asserter asserter; private static final String GET_METHOD_STRING = "GetMethod string"; // Needs to be accessible by Foo.class static final String[] GET_METHOD_ARRAY = new String[] { "One", "Two", "Three" }; // Needs to be accessible by Foo.class static final String[][] GET_METHOD_ARRAY2 = new String[][] { {"One", "Two", "Three"},{"Four", "Five", "Six"} }; @Override public void setUp() { asserter = new Asserter(JEXL); } /** * test simple array access */ public void testArrayAccess() throws Exception { /* * test List access */ List l = new ArrayList(); l.add(new Integer(1)); l.add(new Integer(2)); l.add(new Integer(3)); asserter.setVariable("list", l); asserter.assertExpression("list[1]", new Integer(2)); asserter.assertExpression("list[1+1]", new Integer(3)); asserter.setVariable("loc", new Integer(1)); asserter.assertExpression("list[loc+1]", new Integer(3)); /* * test array access */ String[] args = { "hello", "there" }; asserter.setVariable("array", args); asserter.assertExpression("array[0]", "hello"); /* * to think that this was an intentional syntax... */ asserter.assertExpression("array.0", "hello"); /* * test map access */ Map m = new HashMap(); m.put("foo", "bar"); asserter.setVariable("map", m); asserter.setVariable("key", "foo"); asserter.assertExpression("map[\"foo\"]", "bar"); asserter.assertExpression("map[key]", "bar"); /* * test bean access */ asserter.setVariable("foo", new Foo()); asserter.assertExpression("foo[\"bar\"]", GET_METHOD_STRING); asserter.assertExpression("foo[\"bar\"] == foo.bar", Boolean.TRUE); } /** * test some simple double array lookups */ public void testDoubleArrays() throws Exception { Object[][] foo = new Object[2][2]; foo[0][0] = "one"; foo[0][1] = "two"; asserter.setVariable("foo", foo); asserter.assertExpression("foo[0][1]", "two"); } public void testArrayProperty() throws Exception { Foo foo = new Foo(); asserter.setVariable("foo", foo); asserter.assertExpression("foo.array[1]", GET_METHOD_ARRAY[1]); asserter.assertExpression("foo.array.1", GET_METHOD_ARRAY[1]); asserter.assertExpression("foo.array2[1][1]", GET_METHOD_ARRAY2[1][1]); asserter.assertExpression("foo.array2[1].1", GET_METHOD_ARRAY2[1][1]); } // This is JEXL-26 public void testArrayAndDottedConflict() throws Exception { Object[] objects = new Object[] {"an", "array", new Long(0)}; asserter.setVariable("objects", objects); asserter.setVariable("status", "Enabled"); asserter.assertExpression("objects[1].status", null); asserter.assertExpression("objects.1.status", null); asserter.setVariable("base.status", "Ok"); asserter.assertExpression("base.objects[1].status", null); asserter.assertExpression("base.objects.1.status", null); } public void testArrayMethods() throws Exception { Object[] objects = new Object[] {"an", "array", new Long(0)}; asserter.setVariable("objects", objects); asserter.assertExpression("objects.get(1)", "array"); asserter.assertExpression("objects.size()", new Integer(3)); // setting an index returns the old value asserter.assertExpression("objects.set(1, 'dion')", "array"); asserter.assertExpression("objects[1]", "dion"); } public void testArrayArray() throws Exception { Integer i42 = Integer.valueOf(42); Integer i43 = Integer.valueOf(43); String s42 = "fourty-two"; String s43 = "fourty-three"; Object[] foo = new Object[3]; foo[0] = foo; foo[1] = i42; foo[2] = s42; asserter.setVariable("foo", foo); asserter.setVariable("zero", Integer.valueOf(0)); asserter.setVariable("one", Integer.valueOf(1)); asserter.setVariable("two", Integer.valueOf(2)); for(int l = 0; l < 2; ++l) { asserter.assertExpression("foo[0]", foo); asserter.assertExpression("foo[0][0]", foo); asserter.assertExpression("foo[1]", foo[1]); asserter.assertExpression("foo[0][1]", foo[1]); asserter.assertExpression("foo[0][1] = 43", i43); asserter.assertExpression("foo[0][1]", i43); asserter.assertExpression("foo[0][1] = 42", i42); asserter.assertExpression("foo[0][1]", i42); asserter.assertExpression("foo[0][0][1]", foo[1]); asserter.assertExpression("foo[0][0][1] = 43", i43); asserter.assertExpression("foo[0][0][1]", i43); asserter.assertExpression("foo[0][0][1] = 42", i42); asserter.assertExpression("foo[0][0][1]", i42); asserter.assertExpression("foo[2]", foo[2]); asserter.assertExpression("foo[0][2]", foo[2]); asserter.assertExpression("foo[0][2] = 'fourty-three'", s43); asserter.assertExpression("foo[0][2]", s43); asserter.assertExpression("foo[0][2] = 'fourty-two'", s42); asserter.assertExpression("foo[0][2]", s42); asserter.assertExpression("foo[0][0][2]", foo[2]); asserter.assertExpression("foo[0][0][2] = 'fourty-three'", s43); asserter.assertExpression("foo[0][0][2]", s43); asserter.assertExpression("foo[0][0][2] = 'fourty-two'", s42); asserter.assertExpression("foo[0][0][2]", s42); asserter.assertExpression("foo[zero]", foo); asserter.assertExpression("foo[zero][zero]", foo); asserter.assertExpression("foo[one]", foo[1]); asserter.assertExpression("foo[zero][one]", foo[1]); asserter.assertExpression("foo[zero][one] = 43", i43); asserter.assertExpression("foo[zero][one]", i43); asserter.assertExpression("foo[zero][one] = 42", i42); asserter.assertExpression("foo[zero][one]", i42); asserter.assertExpression("foo[zero][zero][one]", foo[1]); asserter.assertExpression("foo[zero][zero][one] = 43", i43); asserter.assertExpression("foo[zero][zero][one]", i43); asserter.assertExpression("foo[zero][zero][one] = 42", i42); asserter.assertExpression("foo[zero][zero][one]", i42); asserter.assertExpression("foo[two]", foo[2]); asserter.assertExpression("foo[zero][two]", foo[2]); asserter.assertExpression("foo[zero][two] = 'fourty-three'", s43); asserter.assertExpression("foo[zero][two]", s43); asserter.assertExpression("foo[zero][two] = 'fourty-two'", s42); asserter.assertExpression("foo[zero][two]", s42); asserter.assertExpression("foo[zero][zero][two]", foo[2]); asserter.assertExpression("foo[zero][zero][two] = 'fourty-three'", s43); asserter.assertExpression("foo[zero][zero][two]", s43); asserter.assertExpression("foo[zero][zero][two] = 'fourty-two'", s42); asserter.assertExpression("foo[zero][zero][two]", s42); } } }commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/ArrayLiteralTest.java100644 0 0 7724 11673634321 25356 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.Arrays; /** * Tests for array literals * @since 2.0 */ public class ArrayLiteralTest extends JexlTestCase { public void testLiteralWithStrings() throws Exception { Expression e = JEXL.createExpression( "[ 'foo' , 'bar' ]" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); Object[] check = { "foo", "bar" }; assertTrue( Arrays.equals(check, (Object[])o) ); } public void testLiteralWithOneEntry() throws Exception { Expression e = JEXL.createExpression( "[ 'foo' ]" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); Object[] check = { "foo" }; assertTrue( Arrays.equals(check, (Object[])o) ); } public void testLiteralWithNumbers() throws Exception { Expression e = JEXL.createExpression( "[ 5.0 , 10 ]" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); Object[] check = { new Float(5), new Integer(10) }; assertTrue( Arrays.equals(check, (Object[])o) ); assertTrue (o.getClass().isArray() && o.getClass().getComponentType().equals(Number.class)); } public void testLiteralWithNulls() throws Exception { String []exprs = { "[ null , 10 ]", "[ 10 , null ]", "[ 10 , null , 10]", "[ '10' , null ]", "[ null, '10' , null ]" }; Object [][]checks = { {null, new Integer(10)}, {new Integer(10), null}, {new Integer(10), null, new Integer(10)}, { "10", null }, { null, "10", null } }; JexlContext jc = new MapContext(); for(int t = 0; t < exprs.length; ++t) { Expression e = JEXL.createExpression( exprs[t] ); Object o = e.evaluate( jc ); assertTrue(exprs[t], Arrays.equals(checks[t], (Object[])o) ); } } public void testLiteralWithIntegers() throws Exception { Expression e = JEXL.createExpression( "[ 5 , 10 ]" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); int[] check = { 5, 10 }; assertTrue( Arrays.equals(check, (int[])o) ); } public void testSizeOfSimpleArrayLiteral() throws Exception { Expression e = JEXL.createExpression( "size([ 'foo' , 'bar' ])" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); assertEquals( new Integer( 2 ), o ); } public void notestCallingMethodsOnNewMapLiteral() throws Exception { Expression e = JEXL.createExpression( "size({ 'foo' : 'bar' }.values())" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); assertEquals( new Integer( 1 ), o ); } public void testNotEmptySimpleArrayLiteral() throws Exception { Expression e = JEXL.createExpression( "empty([ 'foo' , 'bar' ])" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); assertFalse( ( (Boolean) o ).booleanValue() ); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/AssignTest.java100644 0 0 13622 11673634320 24220 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Test cases for assignment. * * @since 1.1 */ public class AssignTest extends JexlTestCase { private static final JexlArithmetic ARITH = new JexlArithmetic(false); private static final JexlEngine ENGINE = new JexlEngine(null, ARITH, null, null); static { ENGINE.setSilent(false); } public static class Froboz { int value; public Froboz(int v) { value = v; } public void setValue(int v) { value = v; } public int getValue() { return value; } } public static class Quux { String str; Froboz froboz; public Quux(String str, int fro) { this.str = str; froboz = new Froboz(fro); } public Froboz getFroboz() { return froboz; } public void setFroboz(Froboz froboz) { this.froboz = froboz; } public String getStr() { return str; } public void setStr(String str) { this.str = str; } } public AssignTest(String testName) { super(testName); } /** * Make sure bean assignment works * * @throws Exception on any error */ public void testAntish() throws Exception { Expression assign = ENGINE.createExpression("froboz.value = 10"); Expression check = ENGINE.createExpression("froboz.value"); JexlContext jc = new MapContext(); Object o = assign.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); o = check.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); } public void testAntishInteger() throws Exception { Expression assign = ENGINE.createExpression("froboz.0 = 10"); Expression check = ENGINE.createExpression("froboz.0"); JexlContext jc = new MapContext(); Object o = assign.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); o = check.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); } public void testBeanish() throws Exception { Expression assign = ENGINE.createExpression("froboz.value = 10"); Expression check = ENGINE.createExpression("froboz.value"); JexlContext jc = new MapContext(); Froboz froboz = new Froboz(-169); jc.set("froboz", froboz); Object o = assign.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); o = check.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); } public void testAmbiguous() throws Exception { Expression assign = ENGINE.createExpression("froboz.nosuchbean = 10"); JexlContext jc = new MapContext(); Froboz froboz = new Froboz(-169); jc.set("froboz", froboz); Object o = null; try { o = assign.evaluate(jc); } catch(RuntimeException xrt) { String str = xrt.toString(); assertTrue(str.contains("nosuchbean")); return; } finally { assertEquals("Should have failed", null, o); } } public void testArray() throws Exception { Expression assign = ENGINE.createExpression("froboz[\"value\"] = 10"); Expression check = ENGINE.createExpression("froboz[\"value\"]"); JexlContext jc = new MapContext(); Froboz froboz = new Froboz(0); jc.set("froboz", froboz); Object o = assign.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); o = check.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); } public void testMore() throws Exception { JexlContext jc = new MapContext(); jc.set("quuxClass", Quux.class); Expression create = ENGINE.createExpression("quux = new(quuxClass, 'xuuq', 100)"); Expression assign = ENGINE.createExpression("quux.froboz.value = 10"); Expression check = ENGINE.createExpression("quux[\"froboz\"].value"); Quux quux = (Quux) create.evaluate(jc); assertNotNull("quux is null", quux); Object o = assign.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); o = check.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); } public void testUtil() throws Exception { Quux quux = ENGINE.newInstance(Quux.class, "xuuq", Integer.valueOf(100)); ENGINE.setProperty(quux, "froboz.value", Integer.valueOf(100)); Object o = ENGINE.getProperty(quux, "froboz.value"); assertEquals("Result is not 100", new Integer(100), o); ENGINE.setProperty(quux, "['froboz'].value", Integer.valueOf(1000)); o = ENGINE.getProperty(quux, "['froboz']['value']"); assertEquals("Result is not 1000", new Integer(1000), o); } }commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/BitwiseOperatorTest.java100644 0 0 12121 11673634320 26107 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import org.apache.commons.jexl2.junit.Asserter; /** * Tests for the bitwise operators. * @since 1.1 */ public class BitwiseOperatorTest extends JexlTestCase { private Asserter asserter; @Override public void setUp() { asserter = new Asserter(JEXL); } /** * Create the named test. * @param name test name */ public BitwiseOperatorTest(String name) { super(name); } public void testAndWithTwoNulls() throws Exception { asserter.assertExpression("null & null", new Long(0)); } public void testAndWithLeftNull() throws Exception { asserter.assertExpression("null & 1", new Long(0)); } public void testAndWithRightNull() throws Exception { asserter.assertExpression("1 & null", new Long(0)); } public void testAndSimple() throws Exception { asserter.assertExpression("15 & 3", new Long(15 & 3)); } public void testAndVariableNumberCoercion() throws Exception { asserter.setVariable("x", new Integer(15)); asserter.setVariable("y", new Short((short)7)); asserter.assertExpression("x & y", new Long(15 & 7)); } public void testAndVariableStringCoercion() throws Exception { asserter.setVariable("x", new Integer(15)); asserter.setVariable("y", "7"); asserter.assertExpression("x & y", new Long(15 & 7)); } public void testComplementWithNull() throws Exception { asserter.assertExpression("~null", new Long(-1)); } public void testComplementSimple() throws Exception { asserter.assertExpression("~128", new Long(-129)); } public void testComplementVariableNumberCoercion() throws Exception { asserter.setVariable("x", new Integer(15)); asserter.assertExpression("~x", new Long(~15)); } public void testComplementVariableStringCoercion() throws Exception { asserter.setVariable("x", "15"); asserter.assertExpression("~x", new Long(~15)); } public void testOrWithTwoNulls() throws Exception { asserter.assertExpression("null | null", new Long(0)); } public void testOrWithLeftNull() throws Exception { asserter.assertExpression("null | 1", new Long(1)); } public void testOrWithRightNull() throws Exception { asserter.assertExpression("1 | null", new Long(1)); } public void testOrSimple() throws Exception { asserter.assertExpression("12 | 3", new Long(15)); } public void testOrVariableNumberCoercion() throws Exception { asserter.setVariable("x", new Integer(12)); asserter.setVariable("y", new Short((short) 3)); asserter.assertExpression("x | y", new Long(15)); } public void testOrVariableStringCoercion() throws Exception { asserter.setVariable("x", new Integer(12)); asserter.setVariable("y", "3"); asserter.assertExpression("x | y", new Long(15)); } public void testXorWithTwoNulls() throws Exception { asserter.assertExpression("null ^ null", new Long(0)); } public void testXorWithLeftNull() throws Exception { asserter.assertExpression("null ^ 1", new Long(1)); } public void testXorWithRightNull() throws Exception { asserter.assertExpression("1 ^ null", new Long(1)); } public void testXorSimple() throws Exception { asserter.assertExpression("1 ^ 3", new Long(1 ^ 3)); } public void testXorVariableNumberCoercion() throws Exception { asserter.setVariable("x", new Integer(1)); asserter.setVariable("y", new Short((short) 3)); asserter.assertExpression("x ^ y", new Long(1 ^ 3)); } public void testXorVariableStringCoercion() throws Exception { asserter.setVariable("x", new Integer(1)); asserter.setVariable("y", "3"); asserter.assertExpression("x ^ y", new Long(1 ^ 3)); } public void testParenthesized() throws Exception { asserter.assertExpression("(2 | 1) & 3", Long.valueOf(3L)); asserter.assertExpression("(2 & 1) | 3", Long.valueOf(3L)); asserter.assertExpression("~(120 | 42)", new Long( ~(120 | 42) )); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/BlockTest.java100644 0 0 5700 11673634320 24004 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Tests for blocks * @since 1.1 */ public class BlockTest extends JexlTestCase { /** * Create the test * * @param testName name of the test */ public BlockTest(String testName) { super(testName); } public void testBlockSimple() throws Exception { Expression e = JEXL.createExpression("if (true) { 'hello'; }"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertEquals("Result is wrong", "hello", o); } public void testBlockExecutesAll() throws Exception { Expression e = JEXL.createExpression("if (true) { x = 'Hello'; y = 'World';}"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertEquals("First result is wrong", "Hello", jc.get("x")); assertEquals("Second result is wrong", "World", jc.get("y")); assertEquals("Block result is wrong", "World", o); } public void testEmptyBlock() throws Exception { Expression e = JEXL.createExpression("if (true) { }"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertNull("Result is wrong", o); } public void testBlockLastExecuted01() throws Exception { Expression e = JEXL.createExpression("if (true) { x = 1; } else { x = 2; }"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertEquals("Block result is wrong", new Integer(1), o); } public void testBlockLastExecuted02() throws Exception { Expression e = JEXL.createExpression("if (false) { x = 1; } else { x = 2; }"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertEquals("Block result is wrong", new Integer(2), o); } public void testNestedBlock() throws Exception { Expression e = JEXL.createExpression("if (true) { x = 'hello'; y = 'world';" + " if (true) { x; } y; }"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertEquals("Block result is wrong", "world", o); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/CacheTest.java100644 0 0 55212 11673634317 24006 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.List; import java.util.Map; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * Verifies cache & tryExecute */ public class CacheTest extends JexlTestCase { public CacheTest(String testName) { super(testName); } private static final JexlEngine jexl = createEngine(false); static { jexl.setCache(512); jexl.setSilent(false); } @Override public void setUp() throws Exception { // ensure jul logging is only error to avoid warning in silent mode java.util.logging.Logger.getLogger(JexlEngine.class.getName()).setLevel(java.util.logging.Level.SEVERE); } // LOOPS & THREADS private static final int LOOPS = 4096; private static final int NTHREADS = 4; // A pseudo random mix of accessors private static final int[] MIX = { 0, 0, 3, 3, 4, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 2, 2, 3, 3, 0 }; @Override protected void tearDown() throws Exception { debuggerCheck(jexl); } /** * A set of classes that define different getter/setter methods for the same properties. * The goal is to verify that the cached JexlPropertyGet / JexlPropertySet in the AST Nodes are indeed * volatile and do not generate errors even when multiple threads concurently hammer them. */ public static class Cached { public String compute(String arg) { if (arg == null) { arg = "na"; } return getClass().getSimpleName() + "@s#" + arg; } public String compute(String arg0, String arg1) { if (arg0 == null) { arg0 = "na"; } if (arg1 == null) { arg1 = "na"; } return getClass().getSimpleName() + "@s#" + arg0 + ",s#" + arg1; } public String compute(Integer arg) { return getClass().getSimpleName() + "@i#" + arg; } public String compute(float arg) { return getClass().getSimpleName() + "@f#" + arg; } public String compute(int arg0, int arg1) { return getClass().getSimpleName() + "@i#" + arg0 + ",i#" + arg1; } public String ambiguous(Integer arg0, int arg1) { return getClass().getSimpleName() + "!i#" + arg0 + ",i#" + arg1; } public String ambiguous(int arg0, Integer arg1) { return getClass().getSimpleName() + "!i#" + arg0 + ",i#" + arg1; } public static String COMPUTE(String arg) { if (arg == null) { arg = "na"; } return "CACHED@s#" + arg; } public static String COMPUTE(String arg0, String arg1) { if (arg0 == null) { arg0 = "na"; } if (arg1 == null) { arg1 = "na"; } return "CACHED@s#" + arg0 + ",s#" + arg1; } public static String COMPUTE(int arg) { return "CACHED@i#" + arg; } public static String COMPUTE(int arg0, int arg1) { return "CACHED@i#" + arg0 + ",i#" + arg1; } } public static class Cached0 extends Cached { protected String value = "Cached0:new"; protected Boolean flag = Boolean.FALSE; public Cached0() { } public String getValue() { return value; } public void setValue(String arg) { if (arg == null) { arg = "na"; } value = "Cached0:" + arg; } public void setFlag(boolean b) { flag = Boolean.valueOf(b); } public boolean isFlag() { return flag.booleanValue(); } } public static class Cached1 extends Cached0 { @Override public void setValue(String arg) { if (arg == null) { arg = "na"; } value = "Cached1:" + arg; } } public static class Cached2 extends Cached { boolean flag = false; protected String value; public Cached2() { value = "Cached2:new"; } public Object get(String prop) { if ("value".equals(prop)) { return value; } else if ("flag".equals(prop)) { return Boolean.valueOf(flag); } throw new RuntimeException("no such property"); } public void set(String p, Object v) { if (v == null) { v = "na"; } if ("value".equals(p)) { value = getClass().getSimpleName() + ":" + v; } else if ("flag".equals(p)) { flag = Boolean.parseBoolean(v.toString()); } else { throw new RuntimeException("no such property"); } } } public static class Cached3 extends java.util.TreeMap { private static final long serialVersionUID = 1L; boolean flag = false; public Cached3() { put("value", "Cached3:new"); put("flag", "false"); } @Override public Object get(Object key) { return super.get(key.toString()); } @Override public Object put(String key, Object arg) { if (arg == null) { arg = "na"; } arg = "Cached3:" + arg; return super.put(key, arg); } public void setflag(boolean b) { flag = b; } public boolean isflag() { return flag; } } public static class Cached4 extends java.util.ArrayList { private static final long serialVersionUID = 1L; public Cached4() { super.add("Cached4:new"); super.add("false"); } public String getValue() { return super.get(0); } public void setValue(String arg) { if (arg == null) { arg = "na"; } super.set(0, "Cached4:" + arg); } public void setflag(Boolean b) { super.set(1, b.toString()); } public boolean isflag() { return Boolean.parseBoolean(super.get(1)); } } /** * A helper class to pass arguments in tests (instances of getter/setter exercising classes). */ static class TestCacheArguments { Cached0 c0 = new Cached0(); Cached1 c1 = new Cached1(); Cached2 c2 = new Cached2(); Cached3 c3 = new Cached3(); Cached4 c4 = new Cached4(); Object[] ca = { c0, c1, c2, c3, c4 }; Object[] value = null; } /** * Run same test function in NTHREADS in parallel. * @param ctask the task / test * @param loops number of loops to perform * @param cache whether jexl cache is used or not * @throws Exception if anything goes wrong */ @SuppressWarnings("boxing") void runThreaded(Class ctask, int loops, boolean cache) throws Exception { if (loops == 0) { loops = MIX.length; } if (cache) { jexl.setCache(32); } else { jexl.setCache(0); } java.util.concurrent.ExecutorService execs = java.util.concurrent.Executors.newFixedThreadPool(NTHREADS); List> tasks = new ArrayList>(NTHREADS); for(int t = 0; t < NTHREADS; ++t) { tasks.add(jexl.newInstance(ctask, loops)); } // let's not wait for more than a minute List> futures = execs.invokeAll(tasks, 60, TimeUnit.SECONDS); // check that all returned loops for(Future future : futures) { assertEquals(Integer.valueOf(loops), future.get()); } } /** * The base class for MT tests. */ public abstract static class Task implements Callable { final TestCacheArguments args = new TestCacheArguments(); final int loops; final Map vars = new HashMap(); final JexlContext jc = new MapContext(vars); Task(int loops) { this.loops = loops; } public abstract Integer call() throws Exception; /** * The actual test function; assigns and checks. *

The expression will be evaluated against different classes in parallel. * This verifies that neither the volatile cache in the AST nor the expression cache in the JEXL engine * induce errors.

*

* Using it as a micro benchmark, it shows creating expression as the dominating cost; the expression * cache takes care of this. * By moving the expression creations out of the main loop, it also shows that the volatile cache speeds * things up around 2x. *

* @param value the argument value to control * @return the number of loops performed */ public Integer runAssign(Object value) { args.value = new Object[]{value}; Object result; Expression cacheGetValue = jexl.createExpression("cache.value"); Expression cacheSetValue = jexl.createExpression("cache.value = value"); for (int l = 0; l < loops; ++l) { int px = (int) Thread.currentThread().getId(); int mix = MIX[(l + px) % MIX.length]; vars.put("cache", args.ca[mix]); vars.put("value", args.value[0]); result = cacheSetValue.evaluate(jc); if (args.value[0] == null) { assertNull(cacheSetValue.toString(), result); } else { assertEquals(cacheSetValue.toString(), args.value[0], result); } result = cacheGetValue.evaluate(jc); if (args.value[0] == null) { assertEquals(cacheGetValue.toString(), "Cached" + mix + ":na", result); } else { assertEquals(cacheGetValue.toString(), "Cached" + mix + ":" + args.value[0], result); } } return Integer.valueOf(loops); } } /** * A task to check assignment. */ public static class AssignTask extends Task { public AssignTask(int loops) { super(loops); } @Override public Integer call() throws Exception { return runAssign("foo"); } } /** * A task to check null assignment. */ public static class AssignNullTask extends Task { public AssignNullTask(int loops) { super(loops); } @Override public Integer call() throws Exception { return runAssign(null); } } /** * A task to check boolean assignment. */ public static class AssignBooleanTask extends Task { public AssignBooleanTask(int loops) { super(loops); } @Override public Integer call() throws Exception { return runAssignBoolean(Boolean.TRUE); } /** The actual test function. */ private Integer runAssignBoolean(Boolean value) { args.value = new Object[]{value}; Expression cacheGetValue = jexl.createExpression("cache.flag"); Expression cacheSetValue = jexl.createExpression("cache.flag = value"); Object result; for (int l = 0; l < loops; ++l) { int px = (int) Thread.currentThread().getId(); int mix = MIX[(l + px) % MIX.length]; vars.put("cache", args.ca[mix]); vars.put("value", args.value[0]); result = cacheSetValue.evaluate(jc); assertEquals(cacheSetValue.toString(), args.value[0], result); result = cacheGetValue.evaluate(jc); assertEquals(cacheGetValue.toString(), args.value[0], result); } return Integer.valueOf(loops); } } /** * A task to check list assignment. */ public static class AssignListTask extends Task { public AssignListTask(int loops) { super(loops); } @Override public Integer call() throws Exception { return runAssignList(); } /** The actual test function. */ private Integer runAssignList() { args.value = new Object[]{"foo"}; java.util.ArrayList c1 = new java.util.ArrayList(2); c1.add("foo"); c1.add("bar"); args.ca = new Object[]{ new String[]{"one", "two"}, c1 }; Expression cacheGetValue = jexl.createExpression("cache.0"); Expression cacheSetValue = jexl.createExpression("cache[0] = value"); Object result; for (int l = 0; l < loops; ++l) { int px = (int) Thread.currentThread().getId(); int mix = MIX[(l + px) % MIX.length] % args.ca.length; vars.put("cache", args.ca[mix]); vars.put("value", args.value[0]); result = cacheSetValue.evaluate(jc); assertEquals(cacheSetValue.toString(), args.value[0], result); result = cacheGetValue.evaluate(jc); assertEquals(cacheGetValue.toString(), args.value[0], result); } return Integer.valueOf(loops); } } public void testNullAssignNoCache() throws Exception { runThreaded(AssignNullTask.class, LOOPS, false); } public void testNullAssignCache() throws Exception { runThreaded(AssignNullTask.class, LOOPS, true); } public void testAssignNoCache() throws Exception { runThreaded(AssignTask.class, LOOPS, false); } public void testAssignCache() throws Exception { runThreaded(AssignTask.class, LOOPS, true); } public void testAssignBooleanNoCache() throws Exception { runThreaded(AssignBooleanTask.class, LOOPS, false); } public void testAssignBooleanCache() throws Exception { runThreaded(AssignBooleanTask.class, LOOPS, true); } public void testAssignListNoCache() throws Exception { runThreaded(AssignListTask.class, LOOPS, false); } public void testAssignListCache() throws Exception { runThreaded(AssignListTask.class, LOOPS, true); } /** * A task to check method calls. */ public static class ComputeTask extends Task { public ComputeTask(int loops) { super(loops); } @Override public Integer call() throws Exception { args.ca = new Object[]{args.c0, args.c1, args.c2}; args.value = new Object[]{new Integer(2), "quux"}; //jexl.setDebug(true); Expression compute2 = jexl.createExpression("cache.compute(a0, a1)"); Expression compute1 = jexl.createExpression("cache.compute(a0)"); Expression compute1null = jexl.createExpression("cache.compute(a0)"); Expression ambiguous = jexl.createExpression("cache.ambiguous(a0, a1)"); //jexl.setDebug(false); Object result = null; String expected = null; for (int l = 0; l < loops; ++l) { int mix = MIX[l % MIX.length] % args.ca.length; Object value = args.value[l % args.value.length]; vars.put("cache", args.ca[mix]); if (value instanceof String) { vars.put("a0", "S0"); vars.put("a1", "S1"); expected = "Cached" + mix + "@s#S0,s#S1"; } else if (value instanceof Integer) { vars.put("a0", Integer.valueOf(7)); vars.put("a1", Integer.valueOf(9)); expected = "Cached" + mix + "@i#7,i#9"; } else { fail("unexpected value type"); } result = compute2.evaluate(jc); assertEquals(compute2.toString(), expected, result); if (value instanceof Integer) { try { vars.put("a0", Short.valueOf((short) 17)); vars.put("a1", Short.valueOf((short) 19)); result = ambiguous.evaluate(jc); fail("should have thrown an exception"); } catch (JexlException xany) { // throws due to ambiguous exception } } if (value instanceof String) { vars.put("a0", "X0"); expected = "Cached" + mix + "@s#X0"; } else if (value instanceof Integer) { vars.put("a0", Integer.valueOf(5)); expected = "Cached" + mix + "@i#5"; } else { fail("unexpected value type"); } result = compute1.evaluate(jc); assertEquals(compute1.toString(), expected, result); try { vars.put("a0", null); result = compute1null.evaluate(jc); fail("should have thrown an exception"); } catch (JexlException xany) { // throws due to ambiguous exception String sany = xany.getMessage(); String tname = getClass().getName(); if (!sany.startsWith(tname)) { fail("debug mode should carry caller information, " + sany + ", " + tname); } } } return Integer.valueOf(loops); } } public void testComputeNoCache() throws Exception { try { jexl.setDebug(true); runThreaded(ComputeTask.class, LOOPS, false); } finally { jexl.setDebug(false); } } public void testComputeCache() throws Exception { try { jexl.setDebug(true); runThreaded(ComputeTask.class, LOOPS, true); } finally { jexl.setDebug(false); } } /** * The remaining tests exercise the namespaced functions; not MT. * @param x * @param loops * @param cache * @throws Exception */ void doCOMPUTE(TestCacheArguments x, int loops, boolean cache) throws Exception { if (loops == 0) { loops = MIX.length; } if (cache) { jexl.setCache(32); } else { jexl.setCache(0); } Map vars = new HashMap(); JexlContext jc = new MapContext(vars); java.util.Map funcs = new java.util.HashMap(); jexl.setFunctions(funcs); Expression compute2 = jexl.createExpression("cached:COMPUTE(a0, a1)"); Expression compute1 = jexl.createExpression("cached:COMPUTE(a0)"); Object result = null; String expected = null; for (int l = 0; l < loops; ++l) { int mix = MIX[l % MIX.length] % x.ca.length; Object value = x.value[l % x.value.length]; funcs.put("cached", x.ca[mix]); if (value instanceof String) { vars.put("a0", "S0"); vars.put("a1", "S1"); expected = "CACHED@s#S0,s#S1"; } else if (value instanceof Integer) { vars.put("a0", Integer.valueOf(7)); vars.put("a1", Integer.valueOf(9)); expected = "CACHED@i#7,i#9"; } else { fail("unexpected value type"); } result = compute2.evaluate(jc); assertEquals(compute2.toString(), expected, result); if (value instanceof String) { vars.put("a0", "X0"); expected = "CACHED@s#X0"; } else if (value instanceof Integer) { vars.put("a0", Integer.valueOf(5)); expected = "CACHED@i#5"; } else { fail("unexpected value type"); } result = compute1.evaluate(jc); assertEquals(compute1.toString(), expected, result); } } public void testCOMPUTENoCache() throws Exception { TestCacheArguments args = new TestCacheArguments(); args.ca = new Object[]{ Cached.class, Cached1.class, Cached2.class }; args.value = new Object[]{new Integer(2), "quux"}; doCOMPUTE(args, LOOPS, false); } public void testCOMPUTECache() throws Exception { TestCacheArguments args = new TestCacheArguments(); args.ca = new Object[]{ Cached.class, Cached1.class, Cached2.class }; args.value = new Object[]{new Integer(2), "quux"}; doCOMPUTE(args, LOOPS, true); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/ClassCreator.java100644 0 0 12032 11673634320 24513 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; /** * Helper class to test GC / reference interactions. * Dynamically creates a class by compiling generated source Java code and * load it through a dedicated class loader. */ public class ClassCreator { private final JexlEngine jexl; private final File base; private File packageDir = null; private int seed = 0; private String className = null; private String sourceName = null; private ClassLoader loader = null; public static final boolean canRun = comSunToolsJavacMain(); /** * Check if we can invoke Sun's java compiler. * @return true if it is possible, false otherwise */ private static boolean comSunToolsJavacMain() { try { Class javac = ClassCreatorTest.class.getClassLoader().loadClass("com.sun.tools.javac.Main"); return javac != null; } catch (Exception xany) { return false; } } public ClassCreator(JexlEngine theJexl, File theBase) throws Exception { jexl = theJexl; base = theBase; } public void clear() { seed = 0; packageDir = null; className = null; sourceName = null; packageDir = null; loader = null; } public void setSeed(int s) { seed = s; className = "foo" + s; sourceName = className + ".java"; packageDir = new File(base, seed + "/org/apache/commons/jexl2/generated"); packageDir.mkdirs(); loader = null; } public String getClassName() { return "org.apache.commons.jexl2.generated." + className; } public Class getClassInstance() throws Exception { return getClassLoader().loadClass("org.apache.commons.jexl2.generated." + className); } public ClassLoader getClassLoader() throws Exception { if (loader == null) { URL classpath = (new File(base, Integer.toString(seed))).toURI().toURL(); loader = new URLClassLoader(new URL[]{classpath}, null); } return loader; } public Class createClass() throws Exception { // generate, compile & validate generate(); Class clazz = compile(); if (clazz == null) { throw new Exception("failed to compile foo" + seed); } Object v = validate(clazz); if (v instanceof Integer && ((Integer) v).intValue() == seed) { return clazz; } throw new Exception("failed to validate foo" + seed); } void generate() throws Exception { FileWriter aWriter = new FileWriter(new File(packageDir, sourceName), false); aWriter.write("package org.apache.commons.jexl2.generated;"); aWriter.write("public class " + className + "{\n"); aWriter.write("private int value ="); aWriter.write(Integer.toString(seed)); aWriter.write(";\n"); aWriter.write(" public void setValue(int v) {"); aWriter.write(" value = v;"); aWriter.write(" }\n"); aWriter.write(" public int getValue() {"); aWriter.write(" return value;"); aWriter.write(" }\n"); aWriter.write(" }\n"); aWriter.flush(); aWriter.close(); } Class compile() throws Exception { String source = packageDir.getPath() + "/" + sourceName; Class javac = getClassLoader().loadClass("com.sun.tools.javac.Main"); if (javac == null) { return null; } Integer r = (Integer) jexl.invokeMethod(javac, "compile", source); if (r.intValue() >= 0) { return getClassLoader().loadClass("org.apache.commons.jexl2.generated." + className); } return null; } Object validate(Class clazz) throws Exception { Class params[] = {}; Object paramsObj[] = {}; Object iClass = clazz.newInstance(); Method thisMethod = clazz.getDeclaredMethod("getValue", params); return thisMethod.invoke(iClass, paramsObj); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/ClassCreatorTest.java100644 0 0 15741 11673634320 25365 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.io.File; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Basic check on automated class creation */ public class ClassCreatorTest extends JexlTestCase { static final Log logger = LogFactory.getLog(JexlTestCase.class); static final int LOOPS = 8; private File base = null; private JexlEngine jexl = null; @Override public void setUp() throws Exception { base = new File(System.getProperty("java.io.tmpdir") + File.pathSeparator + "jexl" + System.currentTimeMillis()); jexl = new JexlEngine(); jexl.setCache(512); } @Override public void tearDown() throws Exception { deleteDirectory(base); } private void deleteDirectory(File dir) { if (dir.isDirectory()) { for (File file : dir.listFiles()) { if (file.isFile()) { file.delete(); } } } dir.delete(); } // A space hog class static final int MEGA = 1024 * 1024; public class BigObject { @SuppressWarnings("unused") private final byte[] space = new byte[MEGA]; private final int id; public BigObject(int id) { this.id = id; } public int getId() { return id; } } // A soft reference on class static final class ClassReference extends WeakReference> { ClassReference(Class clazz, ReferenceQueue queue) { super(clazz, queue); } } // A weak reference on instance static final class InstanceReference extends SoftReference { InstanceReference(Object obj, ReferenceQueue queue) { super(obj, queue); } } public void testOne() throws Exception { // abort test if class creator can not run if (!ClassCreator.canRun) { return; } ClassCreator cctor = new ClassCreator(jexl, base); cctor.setSeed(1); Class foo1 = cctor.createClass(); assertEquals("foo1", foo1.getSimpleName()); cctor.clear(); } public void testMany() throws Exception { // abort test if class creator can not run if (!ClassCreator.canRun) { return; } int pass = 0; int gced = -1; ReferenceQueue queue = new ReferenceQueue(); List> stuff = new ArrayList>(); // keeping a reference on methods prevent classes from being GCed // List mm = new ArrayList(); Expression expr = jexl.createExpression("foo.value"); Expression newx = jexl.createExpression("foo = new(clazz)"); JexlContext context = new MapContext(); ClassCreator cctor = new ClassCreator(jexl, base); for (int i = 0; i < LOOPS && gced < 0; ++i) { cctor.setSeed(i); Class clazz; if (pass == 0) { clazz = cctor.createClass(); } else { clazz = cctor.getClassInstance(); if (clazz == null) { assertEquals(i, gced); break; } } // this code verifies the assumption that holding a strong reference to a method prevents // its owning class from being GCed // Method m = clazz.getDeclaredMethod("getValue", new Class[0]); // mm.add(m); // we should not be able to create foox since it is unknown to the Jexl classloader context.set("clazz", cctor.getClassName()); context.set("foo", null); Object z = newx.evaluate(context); assertNull(z); // check with the class itself context.set("clazz", clazz); z = newx.evaluate(context); assertNotNull(clazz + ": class " + i + " could not be instantiated on pass " + pass, z); assertEquals(new Integer(i), expr.evaluate(context)); // with the proper class loader, attempt to create an instance from the class name jexl.setClassLoader(cctor.getClassLoader()); z = newx.evaluate(context); assertTrue(z.getClass().equals(clazz)); assertEquals(new Integer(i), expr.evaluate(context)); cctor.clear(); jexl.setClassLoader(null); // on pass 0, attempt to force GC to run and collect generated classes if (pass == 0) { // add a weak reference on the class stuff.add(new ClassReference(clazz, queue)); // add a soft reference on an instance stuff.add(new InstanceReference(clazz.newInstance(), queue)); // attempt to force GC: // while we still have a MB free, create & store big objects for (int b = 0; b < 64 && Runtime.getRuntime().freeMemory() > MEGA; ++b) { BigObject big = new BigObject(b); stuff.add(new InstanceReference(big, queue)); } // hint it... System.gc(); // let's see if some weak refs got collected boolean qr = false; while (queue.poll() != null) { Reference ref = queue.remove(1); if (ref instanceof ClassReference) { gced = i; qr = true; } } if (qr) { //logger.warn("may have GCed class around " + i); pass = 1; i = 0; } } } if (gced < 0) { logger.warn("unable to force GC"); //assertTrue(gced > 0); } } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/examples/ArrayTest.java100644 0 0 4676 11673634321 25662 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.examples; import org.apache.commons.jexl2.*; import junit.framework.TestCase; import java.util.List; import java.util.ArrayList; /** * Simple example to show how to access arrays. * * @since 1.0 */ public class ArrayTest extends TestCase { /** * An example for array access. */ static void example(Output out) throws Exception { /** * First step is to retrieve an instance of a JexlEngine; * it might be already existing and shared or created anew. */ JexlEngine jexl = new JexlEngine(); /* * Second make a jexlContext and put stuff in it */ JexlContext jc = new MapContext(); List l = new ArrayList(); l.add("Hello from location 0"); Integer two = new Integer(2); l.add(two); jc.set("array", l); Expression e = jexl.createExpression("array[1]"); Object o = e.evaluate(jc); out.print("Object @ location 1 = ", o, two); e = jexl.createExpression("array[0].length()"); o = e.evaluate(jc); out.print("The length of the string at location 0 is : ", o, Integer.valueOf(21)); } /** * Unit test entry point. * @throws Exception */ public void testExample() throws Exception { example(Output.JUNIT); } /** * Command line entry point. * @param args command line arguments * @throws Exception cos jexl does. */ public static void main(String[] args) throws Exception { example(Output.SYSTEM); } }commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/examples/MethodPropertyTest.java100644 0 0 7737 11673634321 27572 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.examples; import org.apache.commons.jexl2.*; import junit.framework.TestCase; /** * Simple example to show how to access method and properties. * * @since 1.0 */ public class MethodPropertyTest extends TestCase { /** * An example for method access. */ public static void example(final Output out) throws Exception { /** * First step is to retrieve an instance of a JexlEngine; * it might be already existing and shared or created anew. */ JexlEngine jexl = new JexlEngine(); /* * Second make a jexlContext and put stuff in it */ JexlContext jc = new MapContext(); /** * The Java equivalents of foo and number for comparison and checking */ Foo foo = new Foo(); Integer number = new Integer(10); jc.set("foo", foo); jc.set("number", number); /* * access a method w/o args */ Expression e = jexl.createExpression("foo.getFoo()"); Object o = e.evaluate(jc); out.print("value returned by the method getFoo() is : ", o, foo.getFoo()); /* * access a method w/ args */ e = jexl.createExpression("foo.convert(1)"); o = e.evaluate(jc); out.print("value of " + e.getExpression() + " is : ", o, foo.convert(1)); e = jexl.createExpression("foo.convert(1+7)"); o = e.evaluate(jc); out.print("value of " + e.getExpression() + " is : ", o, foo.convert(1+7)); e = jexl.createExpression("foo.convert(1+number)"); o = e.evaluate(jc); out.print("value of " + e.getExpression() + " is : ", o, foo.convert(1+number.intValue())); /* * access a property */ e = jexl.createExpression("foo.bar"); o = e.evaluate(jc); out.print("value returned for the property 'bar' is : ", o, foo.get("bar")); } /** * Helper example class. */ public static class Foo { /** * Gets foo. * @return a string. */ public String getFoo() { return "This is from getFoo()"; } /** * Gets an arbitrary property. * @param arg property name. * @return arg prefixed with 'This is the property '. */ public String get(String arg) { return "This is the property " + arg; } /** * Gets a string from the argument. * @param i a long. * @return The argument prefixed with 'The value is : ' */ public String convert(long i) { return "The value is : " + i; } } /** * Unit test entry point. * @throws Exception */ public void testExample() throws Exception { example(Output.JUNIT); } /** * Command line entry point. * @param args command line arguments * @throws Exception cos jexl does. */ public static void main(String[] args) throws Exception { example(Output.SYSTEM); } }commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/examples/Output.java100644 0 0 4073 11673634321 25233 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.examples; import junit.framework.TestCase; /** * Abstracts using a test within Junit or through a main method. */ public abstract class Output { /** * Creates an output using System.out. */ private Output() { // nothing to do } /** * Outputs the actual and value or checks the actual equals the expected value. * @param expr the message to output * @param actual the actual value to output * @param expected the expected value */ public abstract void print(String expr, Object actual, Object expected); /** * The output instance for Junit TestCase calling assertEquals. */ public static final Output JUNIT = new Output() { @Override public void print(String expr, Object actual, Object expected) { TestCase.assertEquals(expr, expected, actual); } }; /** * The output instance for the general outputing to System.out. */ public static final Output SYSTEM = new Output() { @Override public void print(String expr, Object actual, Object expected) { System.out.print(expr); System.out.println(actual); } }; }commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/Foo.java100644 0 0 5444 11673634320 22642 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * A simple bean used for testing purposes * * @since 1.0 */ public class Foo { private boolean beenModified = false; private String property1 = "some value"; public Foo() {} public class Cheezy { public Iterator iterator() { return getCheeseList().iterator(); } } public String bar() { return JexlTest.METHOD_STRING; } public String getBar() { return JexlTest.GET_METHOD_STRING; } public Foo getInnerFoo() { return new Foo(); } public String get(String arg) { return "Repeat : " + arg; } public String convertBoolean(boolean b) { return "Boolean : " + b; } public int getCount() { return 5; } public List getCheeseList() { ArrayList answer = new ArrayList(); answer.add("cheddar"); answer.add("edam"); answer.add("brie"); return answer; } public Cheezy getCheezy() { return new Cheezy(); } public String[] getArray() { return ArrayAccessTest.GET_METHOD_ARRAY; } public String[][] getArray2() { return ArrayAccessTest.GET_METHOD_ARRAY2; } public boolean isSimple() { return true; } public int square(int value) { return value * value; } public boolean getTrueAndModify() { beenModified = true; return true; } public boolean getModified() { return beenModified; } public int getSize() { return 22; } public String getProperty1() { return property1; } public void setProperty1(String newValue) { property1 = newValue; } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/ForEachTest.java100644 0 0 12733 11673634317 24313 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.ArrayList; import java.util.Arrays; import java.util.Map; import java.util.StringTokenizer; /** * Tests for the foreach statement * @since 1.1 */ public class ForEachTest extends JexlTestCase { /** create a named test */ public ForEachTest(String name) { super(name); } public void testForEachWithEmptyStatement() throws Exception { Expression e = JEXL.createExpression("for(item : list) ;"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertNull("Result is not null", o); } public void testForEachWithEmptyList() throws Exception { Expression e = JEXL.createExpression("for(item : list) 1+1"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertNull("Result is not null", o); } public void testForEachWithArray() throws Exception { Expression e = JEXL.createExpression("for(item : list) item"); JexlContext jc = new MapContext(); jc.set("list", new Object[] {"Hello", "World"}); Object o = e.evaluate(jc); assertEquals("Result is not last evaluated expression", "World", o); } public void testForEachWithCollection() throws Exception { Expression e = JEXL.createExpression("for(item : list) item"); JexlContext jc = new MapContext(); jc.set("list", Arrays.asList(new Object[] {"Hello", "World"})); Object o = e.evaluate(jc); assertEquals("Result is not last evaluated expression", "World", o); } public void testForEachWithEnumeration() throws Exception { Expression e = JEXL.createExpression("for(item : list) item"); JexlContext jc = new MapContext(); jc.set("list", new StringTokenizer("Hello,World", ",")); Object o = e.evaluate(jc); assertEquals("Result is not last evaluated expression", "World", o); } public void testForEachWithIterator() throws Exception { Expression e = JEXL.createExpression("for(item : list) item"); JexlContext jc = new MapContext(); jc.set("list", Arrays.asList(new Object[] {"Hello", "World"}).iterator()); Object o = e.evaluate(jc); assertEquals("Result is not last evaluated expression", "World", o); } public void testForEachWithMap() throws Exception { Expression e = JEXL.createExpression("for(item : list) item"); JexlContext jc = new MapContext(); Map map = System.getProperties(); String lastProperty = (String) new ArrayList(map.values()).get(System.getProperties().size() - 1); jc.set("list", map); Object o = e.evaluate(jc); assertEquals("Result is not last evaluated expression", lastProperty, o); } public void testForEachWithBlock() throws Exception { Expression exs0 = JEXL.createExpression("for(in : list) { x = x + in; }"); Expression exs1 = JEXL.createExpression("foreach(item in list) { x = x + item; }"); Expression []exs = { exs0, exs1 }; JexlContext jc = new MapContext(); jc.set("list", new Object[] {"2", "3"}); for(int ex = 0; ex < exs.length; ++ex) { jc.set("x", new Integer(1)); Object o = exs[ex].evaluate(jc); assertEquals("Result is wrong", new Integer(6), o); assertEquals("x is wrong", new Integer(6), jc.get("x")); } } public void testForEachWithListExpression() throws Exception { Expression e = JEXL.createExpression("for(item : list.keySet()) item"); JexlContext jc = new MapContext(); Map map = System.getProperties(); String lastKey = (String) new ArrayList(map.keySet()).get(System.getProperties().size() - 1); jc.set("list", map); Object o = e.evaluate(jc); assertEquals("Result is not last evaluated expression", lastKey, o); } public void testForEachWithProperty() throws Exception { Expression e = JEXL.createExpression("for(item : list.cheeseList) item"); JexlContext jc = new MapContext(); jc.set("list", new Foo()); Object o = e.evaluate(jc); assertEquals("Result is not last evaluated expression", "brie", o); } public void testForEachWithIteratorMethod() throws Exception { Expression e = JEXL.createExpression("for(item : list.cheezy) item"); JexlContext jc = new MapContext(); jc.set("list", new Foo()); Object o = e.evaluate(jc); assertEquals("Result is not last evaluated expression", "brie", o); } }commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/IfTest.java100644 0 0 24505 11673634321 23335 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Test cases for the if statement. * * @since 1.1 */ public class IfTest extends JexlTestCase { public IfTest(String testName) { super(testName); } /** * Make sure if true executes the true statement * * @throws Exception on any error */ public void testSimpleIfTrue() throws Exception { Expression e = JEXL.createExpression("if (true) 1"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertEquals("Result is not 1", new Integer(1), o); } /** * Make sure if false doesn't execute the true statement * * @throws Exception on any error */ public void testSimpleIfFalse() throws Exception { Expression e = JEXL.createExpression("if (false) 1"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertNull("Return value is not empty", o); } /** * Make sure if false executes the false statement * * @throws Exception on any error */ public void testSimpleElse() throws Exception { Expression e = JEXL.createExpression("if (false) 1 else 2;"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertEquals("Result is not 2", new Integer(2), o); } /** * Test the if statement handles blocks correctly * * @throws Exception on any error */ public void testBlockIfTrue() throws Exception { Expression e = JEXL.createExpression("if (true) { 'hello'; }"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertEquals("Result is wrong", "hello", o); } /** * Test the if statement handles blocks in the else statement correctly * * @throws Exception on any error */ public void testBlockElse() throws Exception { Expression e = JEXL.createExpression("if (false) {1} else {2 ; 3}"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertEquals("Result is wrong", new Integer(3), o); } /** * Test the if statement evaluates expressions correctly * * @throws Exception on any error */ public void testIfWithSimpleExpression() throws Exception { Expression e = JEXL.createExpression("if (x == 1) true;"); JexlContext jc = new MapContext(); jc.set("x", new Integer(1)); Object o = e.evaluate(jc); assertEquals("Result is not true", Boolean.TRUE, o); } /** * Test the if statement evaluates arithmetic expressions correctly * * @throws Exception on any error */ public void testIfWithArithmeticExpression() throws Exception { Expression e = JEXL.createExpression("if ((x * 2) + 1 == 5) true;"); JexlContext jc = new MapContext(); jc.set("x", new Integer(2)); Object o = e.evaluate(jc); assertEquals("Result is not true", Boolean.TRUE, o); } /** * Test the if statement evaluates decimal arithmetic expressions correctly * * @throws Exception on any error */ public void testIfWithDecimalArithmeticExpression() throws Exception { Expression e = JEXL.createExpression("if ((x * 2) == 5) true"); JexlContext jc = new MapContext(); jc.set("x", new Float(2.5f)); Object o = e.evaluate(jc); assertEquals("Result is not true", Boolean.TRUE, o); } /** * Test the if statement works with assignment * * @throws Exception on any error */ public void testIfWithAssignment() throws Exception { Expression e = JEXL.createExpression("if ((x * 2) == 5) {y = 1} else {y = 2;}"); JexlContext jc = new MapContext(); jc.set("x", new Float(2.5f)); e.evaluate(jc); Object result = jc.get("y"); assertEquals("y has the wrong value", new Integer(1), result); } /** * Ternary operator condition undefined or null evaluates to false * independantly of engine flags. * @throws Exception */ public void testTernary() throws Exception { JexlEngine jexl = createThreadedArithmeticEngine(true); jexl.setCache(64); JexlContext jc = new MapContext(); Expression e = jexl.createExpression("x.y.z = foo ?'bar':'quux'"); Object o; // undefined foo for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", null); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", Boolean.FALSE); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", Boolean.TRUE); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be bar", "bar", o); o = jc.get("x.y.z"); assertEquals("Should be bar", "bar", o); } debuggerCheck(jexl); } /** * Ternary operator condition undefined or null evaluates to false * independantly of engine flags. * @throws Exception */ public void testTernaryShorthand() throws Exception { JexlEngine jexl = createThreadedArithmeticEngine(true); jexl.setCache(64); JexlContext jc = new MapContext(); Expression e = JEXL.createExpression("x.y.z = foo?:'quux'"); Object o; // undefined foo for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", null); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", Boolean.FALSE); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", Double.NaN); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", ""); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", "false"); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", 0d); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", 0); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be quux", "quux", o); o = jc.get("x.y.z"); assertEquals("Should be quux", "quux", o); } jc.set("foo", "bar"); for (int l = 0; l < 4; ++l) { jexl.setLenient((l & 1) != 0); jexl.setSilent((l & 2) != 0); o = e.evaluate(jc); assertEquals("Should be bar", "bar", o); o = jc.get("x.y.z"); assertEquals("Should be bar", "bar", o); } debuggerCheck(jexl); } } ././@LongLink100644 0 0 150 11673650056 10260 Lustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/internal/introspection/DiscoveryTest.javacommons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/internal/introspection/DiscoveryTest.j100644 0 0 23000 11673634321 30757 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal.introspection; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.jexl2.JexlEngine; import org.apache.commons.jexl2.JexlTestCase; import org.apache.commons.jexl2.introspection.Uberspect; import org.apache.commons.jexl2.internal.Introspector; import org.apache.commons.jexl2.internal.AbstractExecutor; import org.apache.commons.jexl2.internal.PropertyGetExecutor; import org.apache.commons.jexl2.internal.PropertySetExecutor; import org.apache.commons.jexl2.internal.DuckGetExecutor; import org.apache.commons.jexl2.internal.DuckSetExecutor; import org.apache.commons.jexl2.internal.ListGetExecutor; import org.apache.commons.jexl2.internal.ListSetExecutor; import org.apache.commons.jexl2.internal.MapGetExecutor; import org.apache.commons.jexl2.internal.MapSetExecutor; /** * Tests for checking introspection discovery. * * @since 2.0 */ public class DiscoveryTest extends JexlTestCase { public static class Duck { private String value; private String eulav; public Duck(String v, String e) { value = v; eulav = e; } public String get(String prop) { if ("value".equals(prop)) { return value; } if ("eulav".equals(prop)) { return eulav; } return "no such property"; } public void set(String prop, String v) { if ("value".equals(prop)) { value = v; } else if ("eulav".equals(prop)) { eulav = v; } } } public static class Bean { private String value; private String eulav; private boolean flag; public Bean(String v, String e) { value = v; eulav = e; flag = true; } public String getValue() { return value; } public void setValue(String v) { value = v; } public String getEulav() { return eulav; } public void setEulav(String v) { eulav = v; } public boolean isFlag() { return flag; } public void setFlag(boolean f) { flag = f; } } public void testBeanIntrospection() throws Exception { Uberspect uber = JexlEngine.getUberspect(null); Introspector intro = (Introspector) uber; Bean bean = new Bean("JEXL", "LXEJ"); AbstractExecutor.Get get = intro.getGetExecutor(bean, "value"); AbstractExecutor.Set set = intro.getSetExecutor(bean, "value", "foo"); assertTrue("bean property getter", get instanceof PropertyGetExecutor); assertTrue("bean property setter", set instanceof PropertySetExecutor); // introspector and uberspect should return same result assertEquals(get, uber.getPropertyGet(bean, "value", null)); assertEquals(set, uber.getPropertySet(bean, "value", "foo", null)); // different property should return different setter/getter assertFalse(get.equals(intro.getGetExecutor(bean, "eulav"))); assertFalse(set.equals(intro.getSetExecutor(bean, "eulav", "foo"))); // setter returns argument Object bar = set.execute(bean, "bar"); assertEquals("bar", bar); // getter should return last value assertEquals("bar", get.execute(bean)); // tryExecute should succeed on same property Object quux = set.tryExecute(bean, "value", "quux"); assertEquals("quux", quux); assertEquals("quux", get.execute(bean)); // tryExecute should fail on different property assertEquals(AbstractExecutor.TRY_FAILED, set.tryExecute(bean, "eulav", "nope")); } public void testDuckIntrospection() throws Exception { Uberspect uber = JexlEngine.getUberspect(null); Introspector intro = (Introspector) uber; Duck duck = new Duck("JEXL", "LXEJ"); AbstractExecutor.Get get = intro.getGetExecutor(duck, "value"); AbstractExecutor.Set set = intro.getSetExecutor(duck, "value", "foo"); assertTrue("duck property getter", get instanceof DuckGetExecutor); assertTrue("duck property setter", set instanceof DuckSetExecutor); // introspector and uberspect should return same result assertEquals(get, uber.getPropertyGet(duck, "value", null)); assertEquals(set, uber.getPropertySet(duck, "value", "foo", null)); // different property should return different setter/getter assertFalse(get.equals(intro.getGetExecutor(duck, "eulav"))); assertFalse(set.equals(intro.getSetExecutor(duck, "eulav", "foo"))); // setter returns argument Object bar = set.execute(duck, "bar"); assertEquals("bar", bar); // getter should return last value assertEquals("bar", get.execute(duck)); // tryExecute should succeed on same property Object quux = set.tryExecute(duck, "value", "quux"); assertEquals("quux", quux); assertEquals("quux", get.execute(duck)); // tryExecute should fail on different property assertEquals(AbstractExecutor.TRY_FAILED, set.tryExecute(duck, "eulav", "nope")); } public void testListIntrospection() throws Exception { Uberspect uber = JexlEngine.getUberspect(null); Introspector intro = (Introspector) uber; List list = new ArrayList(); list.add("LIST"); list.add("TSIL"); AbstractExecutor.Get get = intro.getGetExecutor(list, Integer.valueOf(1)); AbstractExecutor.Set set = intro.getSetExecutor(list, Integer.valueOf(1), "foo"); assertTrue("list property getter", get instanceof ListGetExecutor); assertTrue("list property setter", set instanceof ListSetExecutor); // introspector and uberspect should return same result assertEquals(get, uber.getPropertyGet(list, Integer.valueOf(1), null)); assertEquals(set, uber.getPropertySet(list, Integer.valueOf(1), "foo", null)); // different property should return different setter/getter assertFalse(get.equals(intro.getGetExecutor(list, Integer.valueOf(0)))); assertFalse(get.equals(intro.getSetExecutor(list, Integer.valueOf(0), "foo"))); // setter returns argument Object bar = set.execute(list, "bar"); assertEquals("bar", bar); // getter should return last value assertEquals("bar", get.execute(list)); // tryExecute should succeed on integer property Object quux = set.tryExecute(list, Integer.valueOf(1), "quux"); assertEquals("quux", quux); // getter should return last value assertEquals("quux", get.execute(list)); // tryExecute should fail on non-integer property class assertEquals(AbstractExecutor.TRY_FAILED, set.tryExecute(list, "eulav", "nope")); } public void testMapIntrospection() throws Exception { Uberspect uber = JexlEngine.getUberspect(null); Introspector intro = (Introspector) uber; Map map = new HashMap(); map.put("value", "MAP"); map.put("eulav", "PAM"); AbstractExecutor.Get get = intro.getGetExecutor(map, "value"); AbstractExecutor.Set set = intro.getSetExecutor(map, "value", "foo"); assertTrue("map property getter", get instanceof MapGetExecutor); assertTrue("map property setter", set instanceof MapSetExecutor); // introspector and uberspect should return same result assertEquals(get, uber.getPropertyGet(map, "value", null)); assertEquals(set, uber.getPropertySet(map, "value", "foo", null)); // different property should return different setter/getter assertFalse(get.equals(intro.getGetExecutor(map, "eulav"))); assertFalse(get.equals(intro.getSetExecutor(map, "eulav", "foo"))); // setter returns argument Object bar = set.execute(map, "bar"); assertEquals("bar", bar); // getter should return last value assertEquals("bar", get.execute(map)); // tryExecute should succeed on same property class Object quux = set.tryExecute(map, "value", "quux"); assertEquals("quux", quux); // getter should return last value assertEquals("quux", get.execute(map)); // tryExecute should fail on different property class assertEquals(AbstractExecutor.TRY_FAILED, set.tryExecute(map, Integer.valueOf(1), "nope")); } } ././@LongLink100644 0 0 150 11673650056 10260 Lustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/internal/introspection/MethodKeyTest.javacommons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/internal/introspection/MethodKeyTest.j100644 0 0 17647 11673634321 30725 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.internal.introspection; import org.apache.commons.jexl2.internal.introspection.MethodKey; import org.apache.commons.jexl2.internal.introspection.ClassMap; import junit.framework.TestCase; /** * Checks the CacheMap.MethodKey implementation */ public class MethodKeyTest extends TestCase { // A set of classes (most of them primitives) private static final Class[] PRIMS = { Boolean.TYPE, Byte.TYPE, Character.TYPE, Double.TYPE, Float.TYPE, Integer.TYPE, Long.TYPE, Short.TYPE, String.class, java.util.Date.class }; // A set of instances corresponding to the classes private static final Object[] ARGS = { new Boolean(true), new Byte((byte) 1), new Character('2'), new Double(4d), new Float(8f), new Integer(16), new Long(32l), new Short((short)64), "foobar", new java.util.Date() }; // A set of (pseudo) method names private static final String[] METHODS = { "plus", "minus", "execute", "activate", "perform", "apply", "invoke", "executeAction", "activateAction", "performAction", "applyAction", "invokeAction", "executeFunctor", "activateFunctor", "performFunctor", "applyFunctor", "invokeFunctor", "executeIt", "activateIt", "performIt", "applyIt", "invokeIt" }; /** from key to string */ private static final java.util.Map< MethodKey, String> byKey; /** form string to key */ private static final java.util.Map byString; /** the list of keys we generated & test against */ private static final MethodKey[] keyList; /** Creates & inserts a key into the byKey & byString map */ private static void setUpKey(String name, Class[] parms) { MethodKey key = new MethodKey(name, parms); String str = key.toString(); byKey.put(key, str); byString.put(str, key); } /** Generate a list of method*(prims*), method(prims*, prims*), method*(prims*,prims*,prims*) */ static { byKey = new java.util.HashMap< MethodKey, String>(); byString = new java.util.HashMap(); for (int m = 0; m < METHODS.length; ++m) { String method = METHODS[m]; for (int p0 = 0; p0 < PRIMS.length; ++p0) { Class[] arg0 = {PRIMS[p0]}; setUpKey(method, arg0); for (int p1 = 0; p1 < PRIMS.length; ++p1) { Class[] arg1 = {PRIMS[p0], PRIMS[p1]}; setUpKey(method, arg1); for (int p2 = 0; p2 < PRIMS.length; ++p2) { Class[] arg2 = {PRIMS[p0], PRIMS[p1], PRIMS[p2]}; setUpKey(method, arg2); } } } } keyList = byKey.keySet().toArray(new MethodKey[byKey.size()]); } /** Builds a string key */ String makeStringKey(String method, Class... params) { StringBuilder builder = new StringBuilder(method); for(int p = 0; p < params.length; ++p) { builder.append(ClassMap.MethodCache.primitiveClass(params[p]).getName()); } return builder.toString(); } /** Checks that a string key does exist */ void checkStringKey(String method, Class... params) { String key = makeStringKey(method, params); MethodKey out = byString.get(key); assertTrue(out != null); } /** Builds a method key */ MethodKey makeKey(String method, Class... params) { return new MethodKey(method, params); } /** Checks that a method key exists */ void checkKey(String method, Class... params) { MethodKey key = makeKey(method, params); String out = byKey.get(key); assertTrue(out != null); } public void testObjectKey() throws Exception { for(int k = 0; k < keyList.length; ++k) { MethodKey ctl = keyList[k]; MethodKey key = makeKey(ctl.getMethod(), ctl.getParameters()); String out = byKey.get(key); assertTrue(out != null); assertTrue(ctl.toString() + " != " + out, ctl.toString().equals(out)); } } public void testStringKey() throws Exception { for(int k = 0; k < keyList.length; ++k) { MethodKey ctl = keyList[k]; String key = makeStringKey(ctl.getMethod(), ctl.getParameters()); MethodKey out = byString.get(key); assertTrue(out != null); assertTrue(ctl.toString() + " != " + key, ctl.equals(out)); } } private static final int LOOP = 3;//00; public void testPerfKey() throws Exception { for(int l = 0; l < LOOP; ++l) for(int k = 0; k < keyList.length; ++k) { MethodKey ctl = keyList[k]; MethodKey key = makeKey(ctl.getMethod(), ctl.getParameters()); String out = byKey.get(key); assertTrue(out != null); } } public void testPerfString() throws Exception { for(int l = 0; l < LOOP; ++l) for(int k = 0; k < keyList.length; ++k) { MethodKey ctl = keyList[k]; String key = makeStringKey(ctl.getMethod(), ctl.getParameters()); MethodKey out = byString.get(key); assertTrue(out != null); } } public void testPerfKey2() throws Exception { for(int l = 0; l < LOOP; ++l) for (int m = 0; m < METHODS.length; ++m) { String method = METHODS[m]; for (int p0 = 0; p0 < ARGS.length; ++p0) { checkKey(method, ARGS[p0].getClass()); for (int p1 = 0; p1 < ARGS.length; ++p1) { checkKey(method, ARGS[p0].getClass(), ARGS[p1].getClass()); for (int p2 = 0; p2 < ARGS.length; ++p2) { checkKey(method, ARGS[p0].getClass(), ARGS[p1].getClass(), ARGS[p2].getClass()); } } } } } public void testPerfStringKey2() throws Exception { for(int l = 0; l < LOOP; ++l) for (int m = 0; m < METHODS.length; ++m) { String method = METHODS[m]; for (int p0 = 0; p0 < ARGS.length; ++p0) { checkStringKey(method, ARGS[p0].getClass()); for (int p1 = 0; p1 < ARGS.length; ++p1) { checkStringKey(method, ARGS[p0].getClass(), ARGS[p1].getClass()); for (int p2 = 0; p2 < ARGS.length; ++p2) { checkStringKey(method, ARGS[p0].getClass(), ARGS[p1].getClass(), ARGS[p2].getClass()); } } } } } }commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/IssuesTest.java100644 0 0 75004 11673634320 24251 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.math.BigDecimal; import java.math.BigInteger; import java.math.MathContext; import org.apache.commons.jexl2.introspection.Uberspect; import org.apache.commons.jexl2.internal.Introspector; import java.util.HashMap; import java.util.Map; import org.apache.commons.jexl2.introspection.UberspectImpl; /** * Test cases for reported issues */ @SuppressWarnings("boxing") public class IssuesTest extends JexlTestCase { @Override public void setUp() throws Exception { // ensure jul logging is only error to avoid warning in silent mode java.util.logging.Logger.getLogger(JexlEngine.class.getName()).setLevel(java.util.logging.Level.SEVERE); } // JEXL-24: long integers (and doubles) public void test24() throws Exception { Map vars = new HashMap(); JexlContext ctxt = new MapContext(vars); String stmt = "{a = 10L; b = 10l; c = 42.0D; d = 42.0d; e=56.3F; f=56.3f; g=63.5; h=0x10; i=010; j=0x10L; k=010l}"; Script expr = JEXL.createScript(stmt); /* Object value = */ expr.execute(ctxt); assertEquals(10L, vars.get("a")); assertEquals(10l, vars.get("b")); assertEquals(42.0D, vars.get("c")); assertEquals(42.0d, vars.get("d")); assertEquals(56.3f, vars.get("e")); assertEquals(56.3f, vars.get("f")); assertEquals(63.5f, vars.get("g")); assertEquals(0x10, vars.get("h")); assertEquals(010, vars.get("i")); assertEquals(0x10L, vars.get("j")); assertEquals(010l, vars.get("k")); } // JEXL-24: big integers and big decimals public void test24B() throws Exception { Map vars = new HashMap(); JexlContext ctxt = new MapContext(vars); String stmt = "{a = 10H; b = 10h; c = 42.0B; d = 42.0b;}"; Script expr = JEXL.createScript(stmt); /* Object value = */ expr.execute(ctxt); assertEquals(new BigInteger("10"), vars.get("a")); assertEquals(new BigInteger("10"), vars.get("b")); assertEquals(new BigDecimal("42.0"), vars.get("c")); assertEquals(new BigDecimal("42.0"), vars.get("d")); } // JEXL-24: big decimals with exponent public void test24C() throws Exception { Map vars = new HashMap(); JexlContext ctxt = new MapContext(vars); String stmt = "{a = 42.0e1B; b = 42.0E+2B; c = 42.0e-1B; d = 42.0E-2b;}"; Script expr = JEXL.createScript(stmt); /* Object value = */ expr.execute(ctxt); assertEquals(new BigDecimal("42.0e+1"), vars.get("a")); assertEquals(new BigDecimal("42.0e+2"), vars.get("b")); assertEquals(new BigDecimal("42.0e-1"), vars.get("c")); assertEquals(new BigDecimal("42.0e-2"), vars.get("d")); } // JEXL-24: doubles with exponent public void test24D() throws Exception { Map vars = new HashMap(); JexlContext ctxt = new MapContext(vars); String stmt = "{a = 42.0e1D; b = 42.0E+2D; c = 42.0e-1d; d = 42.0E-2d;}"; Script expr = JEXL.createScript(stmt); /* Object value = */ expr.execute(ctxt); assertEquals(Double.valueOf("42.0e+1"), vars.get("a")); assertEquals(Double.valueOf("42.0e+2"), vars.get("b")); assertEquals(Double.valueOf("42.0e-1"), vars.get("c")); assertEquals(Double.valueOf("42.0e-2"), vars.get("d")); } // JEXL-49: blocks not parsed (fixed) public void test49() throws Exception { Map vars = new HashMap(); JexlContext ctxt = new MapContext(vars); String stmt = "{a = 'b'; c = 'd';}"; Script expr = JEXL.createScript(stmt); /* Object value = */ expr.execute(ctxt); assertTrue("JEXL-49 is not fixed", vars.get("a").equals("b") && vars.get("c").equals("d")); } // JEXL-48: bad assignment detection public static class Another { public String name = "whatever"; private Boolean foo = Boolean.TRUE; public Boolean foo() { return foo; } public int goo() { return 100; } } public static class Foo { private Another inner; Foo() { inner = new Another(); } public Another getInner() { return inner; } } public void test48() throws Exception { JexlEngine jexl = new JexlEngine(); // ensure errors will throw jexl.setSilent(false); String jexlExp = "(foo.getInner().foo() eq true) and (foo.getInner().goo() = (foo.getInner().goo()+1-1))"; Expression e = jexl.createExpression(jexlExp); JexlContext jc = new MapContext(); jc.set("foo", new Foo()); try { /* Object o = */ e.evaluate(jc); fail("Should have failed due to invalid assignment"); } catch (JexlException xjexl) { // expected } } // JEXL-47: C style comments (single & multi line) (fixed in Parser.jjt) // JEXL-44: comments dont allow double quotes (fixed in Parser.jjt) public void test47() throws Exception { JexlEngine jexl = new JexlEngine(); // ensure errors will throw jexl.setSilent(false); JexlContext ctxt = new MapContext(); Expression expr = jexl.createExpression("true//false\n"); Object value = expr.evaluate(ctxt); assertTrue("should be true", ((Boolean) value).booleanValue()); expr = jexl.createExpression("/*true*/false"); value = expr.evaluate(ctxt); assertFalse("should be false", ((Boolean) value).booleanValue()); expr = jexl.createExpression("/*\"true\"*/false"); value = expr.evaluate(ctxt); assertFalse("should be false", ((Boolean) value).booleanValue()); } // JEXL-42: NullPointerException evaluating an expression // fixed in JexlArithmetic by allowing add operator to deal with string, null public void test42() throws Exception { JexlEngine jexl = new JexlEngine(); UnifiedJEXL uel = new UnifiedJEXL(jexl); // ensure errors will throw //jexl.setSilent(false); JexlContext ctxt = new MapContext(); ctxt.set("ax", "ok"); UnifiedJEXL.Expression expr = uel.parse("${ax+(bx)}"); Object value = expr.evaluate(ctxt); assertTrue("should be ok", "ok".equals(value)); } // JEXL-40: failed to discover all methods (non public class implements public method) // fixed in ClassMap by taking newer version of populateCache from Velocity public static abstract class Base { public abstract boolean foo(); } class Derived extends Base { @Override public boolean foo() { return true; } } public void test40() throws Exception { JexlEngine jexl = new JexlEngine(); // ensure errors will throw jexl.setSilent(false); JexlContext ctxt = new MapContext(); ctxt.set("derived", new Derived()); Expression expr = jexl.createExpression("derived.foo()"); Object value = expr.evaluate(ctxt); assertTrue("should be true", ((Boolean) value).booleanValue()); } // JEXL-52: can be implemented by deriving Interpreter.{g,s}etAttribute; later public void test52base() throws Exception { JexlEngine jexl = createEngine(false); Uberspect uber = jexl.getUberspect(); // most likely, call will be in an Interpreter, getUberspect String[] names = ((Introspector) uber).getMethodNames(Another.class); assertTrue("should find methods", names.length > 0); int found = 0; for (String name : names) { if ("foo".equals(name) || "goo".equals(name)) { found += 1; } } assertTrue("should have foo & goo", found == 2); names = ((UberspectImpl) uber).getFieldNames(Another.class); assertTrue("should find fields", names.length > 0); found = 0; for (String name : names) { if ("name".equals(name)) { found += 1; } } assertTrue("should have name", found == 1); } // JEXL-10/JEXL-11: variable checking, null operand is error public void test11() throws Exception { JexlEngine jexl = createEngine(false); // ensure errors will throw jexl.setSilent(false); JexlContext ctxt = new MapContext(); ctxt.set("a", null); String[] exprs = { //"10 + null", //"a - 10", //"b * 10", "a % b"//, //"1000 / a" }; for (int e = 0; e < exprs.length; ++e) { try { Expression expr = jexl.createExpression(exprs[e]); /* Object value = */ expr.evaluate(ctxt); fail(exprs[e] + " : should have failed due to null argument"); } catch (JexlException xjexl) { // expected } } } // JEXL-62 public void test62() throws Exception { JexlContext ctxt; JexlEngine jexl = createEngine(false); jexl.setSilent(true); // to avoid throwing JexlException on null method call Script jscript; ctxt = new MapContext(); jscript = jexl.createScript("dummy.hashCode()"); assertEquals(jscript.getText(), null, jscript.execute(ctxt)); // OK ctxt.set("dummy", "abcd"); assertEquals(jscript.getText(), Integer.valueOf("abcd".hashCode()), jscript.execute(ctxt)); // OK jscript = jexl.createScript("dummy.hashCode"); assertEquals(jscript.getText(), null, jscript.execute(ctxt)); // OK Expression jexpr; ctxt = new MapContext(); jexpr = jexl.createExpression("dummy.hashCode()"); assertEquals(jexpr.getExpression(), null, jexpr.evaluate(ctxt)); // OK ctxt.set("dummy", "abcd"); assertEquals(jexpr.getExpression(), Integer.valueOf("abcd".hashCode()), jexpr.evaluate(ctxt)); // OK jexpr = jexl.createExpression("dummy.hashCode"); assertEquals(jexpr.getExpression(), null, jexpr.evaluate(ctxt)); // OK } // JEXL-73 public void test73() throws Exception { JexlContext ctxt = new MapContext(); JexlEngine jexl = createEngine(false); jexl.setSilent(false); Expression e; e = jexl.createExpression("c.e"); try { /* Object o = */ e.evaluate(ctxt); fail("c.e not declared as variable"); } catch (JexlException.Variable xjexl) { String msg = xjexl.getMessage(); assertTrue(msg.indexOf("c.e") > 0); } ctxt.set("c", "{ 'a' : 3, 'b' : 5}"); ctxt.set("e", Integer.valueOf(2)); try { /* Object o = */ e.evaluate(ctxt); fail("c.e not accessible as property"); } catch (JexlException.Property xjexl) { String msg = xjexl.getMessage(); assertTrue(msg.indexOf("c.e") > 0); } } // JEXL-87 public void test87() throws Exception { JexlContext ctxt = new MapContext(); JexlEngine jexl = createEngine(false); jexl.setSilent(false); Expression divide = jexl.createExpression("l / r"); Expression modulo = jexl.createExpression("l % r"); ctxt.set("l", java.math.BigInteger.valueOf(7)); ctxt.set("r", java.math.BigInteger.valueOf(2)); assertEquals(java.math.BigInteger.valueOf(3), divide.evaluate(ctxt)); assertTrue(jexl.getArithmetic().equals(1, modulo.evaluate(ctxt))); ctxt.set("l", java.math.BigDecimal.valueOf(7)); ctxt.set("r", java.math.BigDecimal.valueOf(2)); assertEquals(java.math.BigDecimal.valueOf(3.5), divide.evaluate(ctxt)); assertTrue(jexl.getArithmetic().equals(1, modulo.evaluate(ctxt))); } // JEXL-90 public void test90() throws Exception { JexlContext ctxt = new MapContext(); JexlEngine jexl = createEngine(false); jexl.setSilent(false); jexl.setCache(16); // ';' is necessary between expressions String[] fexprs = { "a=3 b=4", "while(a) while(a)", "1 2", "if (true) 2; 3 {}", "while (x) 1 if (y) 2 3" }; for (int f = 0; f < fexprs.length; ++f) { try { jexl.createScript(fexprs[f]); fail(fexprs[f] + ": Should have failed in parse"); } catch (JexlException xany) { // expected to fail in parse } } // ';' is necessary between expressions and only expressions String[] exprs = { "if (x) {1} if (y) {2}", "if (x) 1 if (y) 2", "while (x) 1 if (y) 2 else 3", "for(z : [3, 4, 5]) { z } y ? 2 : 1", "for(z : [3, 4, 5]) { z } if (y) 2 else 1" }; ctxt.set("x", Boolean.FALSE); ctxt.set("y", Boolean.TRUE); for (int e = 0; e < exprs.length; ++e) { Script s = jexl.createScript(exprs[e]); assertEquals(Integer.valueOf(2), s.execute(ctxt)); } debuggerCheck(jexl); } // JEXL-44 public void test44() throws Exception { JexlContext ctxt = new MapContext(); JexlEngine jexl = createEngine(false); jexl.setSilent(false); Script script; script = jexl.createScript("'hello world!'//commented"); assertEquals("hello world!", script.execute(ctxt)); script = jexl.createScript("'hello world!';//commented\n'bye...'"); assertEquals("bye...", script.execute(ctxt)); script = jexl.createScript("'hello world!'## commented"); assertEquals("hello world!", script.execute(ctxt)); script = jexl.createScript("'hello world!';## commented\n'bye...'"); assertEquals("bye...", script.execute(ctxt)); } public void test97() throws Exception { JexlContext ctxt = new MapContext(); for (char v = 'a'; v <= 'z'; ++v) { ctxt.set(Character.toString(v), 10); } String input = "(((((((((((((((((((((((((z+y)/x)*w)-v)*u)/t)-s)*r)/q)+p)-o)*n)-m)+l)*k)+j)/i)+h)*g)+f)/e)+d)-c)/b)+a)"; JexlEngine jexl = new JexlEngine(); Expression script; // Make sure everything is loaded... long start = System.nanoTime(); script = jexl.createExpression(input); Object value = script.evaluate(ctxt); assertEquals(Integer.valueOf(11), value); long end = System.nanoTime(); double millisec = (end - start) / 1e6; double limit = 200.0; // Allow plenty of slack assertTrue("Expected parse to take less than " + limit + "ms, actual " + millisec, millisec < limit); } public static class fn98 { public String replace(String str, String target, String replacement) { return str.replace(target, replacement); } } public void test98() throws Exception { String[] exprs = { "fn:replace('DOMAIN\\somename', '\\\\', '\\\\\\\\')", "fn:replace(\"DOMAIN\\somename\", \"\\\\\", \"\\\\\\\\\")", "fn:replace('DOMAIN\\somename', '\\u005c', '\\u005c\\u005c')" }; JexlEngine jexl = new JexlEngine(); Map funcs = new HashMap(); funcs.put("fn", new fn98()); jexl.setFunctions(funcs); for (String expr : exprs) { Object value = jexl.createExpression(expr).evaluate(null); assertEquals(expr, "DOMAIN\\\\somename", value); } } public void test100() throws Exception { JexlEngine jexl = new JexlEngine(); jexl.setCache(4); JexlContext ctxt = new MapContext(); int[] foo = {42}; ctxt.set("foo", foo); Object value; for (int l = 0; l < 2; ++l) { value = jexl.createExpression("foo[0]").evaluate(ctxt); assertEquals(42, value); value = jexl.createExpression("foo[0] = 43").evaluate(ctxt); assertEquals(43, value); value = jexl.createExpression("foo.0").evaluate(ctxt); assertEquals(43, value); value = jexl.createExpression("foo.0 = 42").evaluate(ctxt); assertEquals(42, value); } } // A's class definition public static class A105 { String nameA; String propA; public A105(String nameA, String propA) { this.nameA = nameA; this.propA = propA; } @Override public String toString() { return "A [nameA=" + nameA + ", propA=" + propA + "]"; } public String getNameA() { return nameA; } public String getPropA() { return propA; } } public void test105() throws Exception { JexlContext context = new MapContext(); Expression selectExp = new JexlEngine().createExpression("[a.propA]"); context.set("a", new A105("a1", "p1")); Object[] r = (Object[]) selectExp.evaluate(context); assertEquals("p1", r[0]); //selectExp = new JexlEngine().createExpression("[a.propA]"); context.set("a", new A105("a2", "p2")); r = (Object[]) selectExp.evaluate(context); assertEquals("p2", r[0]); } public void test106() throws Exception { JexlContext context = new MapContext(); context.set("a", new BigDecimal(1)); context.set("b", new BigDecimal(3)); JexlEngine jexl = new JexlEngine(); try { Object value = jexl.createExpression("a / b").evaluate(context); assertNotNull(value); } catch (JexlException xjexl) { fail("should not occur"); } JexlArithmetic arithmetic = new JexlArithmetic(false, MathContext.UNLIMITED, 2); JexlEngine jexlX = new JexlEngine(null, arithmetic, null, null); try { jexlX.createExpression("a / b").evaluate(context); fail("should fail"); } catch (JexlException xjexl) { //ok to fail } } public void test107() throws Exception { String[] exprs = { "'Q4'.toLowerCase()", "q4", "(Q4).toLowerCase()", "q4", "(4).toString()", "4", "(1 + 3).toString()", "4", "({ 'q' : 'Q4'}).get('q').toLowerCase()", "q4", "{ 'q' : 'Q4'}.get('q').toLowerCase()", "q4", "({ 'q' : 'Q4'})['q'].toLowerCase()", "q4", "(['Q4'])[0].toLowerCase()", "q4" }; JexlContext context = new MapContext(); context.set("Q4", "Q4"); JexlEngine jexl = new JexlEngine(); for (int e = 0; e < exprs.length; e += 2) { Expression expr = jexl.createExpression(exprs[e]); Object expected = exprs[e + 1]; Object value = expr.evaluate(context); assertEquals(expected, value); expr = jexl.createExpression(expr.dump()); value = expr.evaluate(context); assertEquals(expected, value); } } public void test108() throws Exception { Expression expr; Object value; JexlEngine jexl = new JexlEngine(); expr = jexl.createExpression("size([])"); value = expr.evaluate(null); assertEquals(0, value); expr = jexl.createExpression(expr.dump()); value = expr.evaluate(null); assertEquals(0, value); expr = jexl.createExpression("if (true) { [] } else { {:} }"); value = expr.evaluate(null); assertTrue(value.getClass().isArray()); expr = jexl.createExpression(expr.dump()); value = expr.evaluate(null); assertTrue(value.getClass().isArray()); expr = jexl.createExpression("size({:})"); value = expr.evaluate(null); assertEquals(0, value); expr = jexl.createExpression(expr.dump()); value = expr.evaluate(null); assertEquals(0, value); expr = jexl.createExpression("if (false) { [] } else { {:} }"); value = expr.evaluate(null); assertTrue(value instanceof Map); expr = jexl.createExpression(expr.dump()); value = expr.evaluate(null); assertTrue(value instanceof Map); } public void test109() throws Exception { JexlEngine jexl = new JexlEngine(); Object value; JexlContext context = new MapContext(); context.set("foo.bar", 40); value = jexl.createExpression("foo.bar + 2").evaluate(context); assertEquals(42, value); } public void test110() throws Exception { JexlEngine jexl = new JexlEngine(); String[] names = {"foo"}; Object value; JexlContext context = new MapContext(); value = jexl.createScript("foo + 2", null, names).execute(context, 40); assertEquals(42, value); context.set("frak.foo", -40); value = jexl.createScript("frak.foo - 2", null, names).execute(context, 40); assertEquals(-42, value); } static public class RichContext extends ObjectContext { RichContext(JexlEngine jexl, A105 a105) { super(jexl, a105); } public String uppercase(String str) { return str.toUpperCase(); } } public void testRichContext() throws Exception { A105 a105 = new A105("foo", "bar"); JexlEngine jexl = new JexlEngine(); Object value; JexlContext context = new RichContext(jexl, a105); value = jexl.createScript("uppercase(nameA + propA)").execute(context); assertEquals("FOOBAR", value); } public void test111() throws Exception { JexlEngine jexl = new JexlEngine(); Object value; JexlContext context = new MapContext(); String strExpr = "((x>0)?\"FirstValue=\"+(y-x):\"SecondValue=\"+x)"; Expression expr = jexl.createExpression(strExpr); context.set("x", 1); context.set("y", 10); value = expr.evaluate(context); assertEquals("FirstValue=9", value); context.set("x", 1.0d); context.set("y", 10.0d); value = expr.evaluate(context); assertEquals("FirstValue=9.0", value); context.set("x", 1); context.set("y", 10.0d); value = expr.evaluate(context); assertEquals("FirstValue=9.0", value); context.set("x", 1.0d); context.set("y", 10); value = expr.evaluate(context); assertEquals("FirstValue=9.0", value); context.set("x", -10); context.set("y", 1); value = expr.evaluate(context); assertEquals("SecondValue=-10", value); context.set("x", -10.0d); context.set("y", 1.0d); value = expr.evaluate(context); assertEquals("SecondValue=-10.0", value); context.set("x", -10); context.set("y", 1.0d); value = expr.evaluate(context); assertEquals("SecondValue=-10", value); context.set("x", -10.0d); context.set("y", 1); value = expr.evaluate(context); assertEquals("SecondValue=-10.0", value); } public void testScaleIssue() throws Exception { JexlArithmetic arithmetic = new JexlThreadedArithmetic(false); JexlEngine jexlX = new JexlEngine(null, arithmetic, null, null); String expStr1 = "result == salary/month * work.percent/100.00"; Expression exp1 = jexlX.createExpression(expStr1); JexlContext ctx = new MapContext(); ctx.set("result", new BigDecimal("9958.33")); ctx.set("salary", new BigDecimal("119500.00")); ctx.set("month", new BigDecimal("12.00")); ctx.set("percent", new BigDecimal("100.00")); // will fail because default scale is 5 assertFalse((Boolean) exp1.evaluate(ctx)); // will succeed with scale = 2 JexlThreadedArithmetic.setMathScale(2); assertTrue((Boolean) exp1.evaluate(ctx)); } public void test112() throws Exception { Object result; JexlEngine jexl = new JexlEngine(); result = jexl.createScript(Integer.toString(Integer.MAX_VALUE)).execute(null); assertEquals(Integer.MAX_VALUE, result); result = jexl.createScript(Integer.toString(Integer.MIN_VALUE + 1)).execute(null); assertEquals(Integer.MIN_VALUE + 1, result); result = jexl.createScript(Integer.toString(Integer.MIN_VALUE)).execute(null); assertEquals(Integer.MIN_VALUE, result); } public void test117() throws Exception { JexlEngine jexl = new JexlEngine(); Expression e = jexl.createExpression("TIMESTAMP > 20100102000000"); JexlContext ctx = new MapContext(); ctx.set("TIMESTAMP", new Long("20100103000000")); Object result = e.evaluate(ctx); assertTrue((Boolean) result); } public void testStringIdentifier() throws Exception { JexlEngine jexl = new JexlEngine(); Map foo = new HashMap(); JexlContext jc = new MapContext(); jc.set("foo", foo); foo.put("q u u x", "456"); Expression e = jexl.createExpression("foo.\"q u u x\""); Object result = e.evaluate(jc); assertEquals("456", result); e = jexl.createExpression("foo.'q u u x'"); result = e.evaluate(jc); assertEquals("456", result); Script s = jexl.createScript("foo.\"q u u x\""); result = s.execute(jc); assertEquals("456", result); s = jexl.createScript("foo.'q u u x'"); result = s.execute(jc); assertEquals("456", result); Debugger dbg = new Debugger(); dbg.debug(((ExpressionImpl) s).script); String dbgdata = dbg.data(); assertEquals("foo.'q u u x';", dbgdata); } public static class Container { String value0; int value1; public Container(String name, int number) { value0 = name; value1 = number; } public Object getProperty(String name) { if ("name".equals(name)) { return value0; } else if ("number".equals(name)) { return value1; } else { return null; } } public Object getProperty(int ref) { if (0 == ref) { return value0; } else if (1 == ref) { return value1; } else { return null; } } public void setProperty(String name, String value) { if ("name".equals(name)) { this.value0 = value; } } public void setProperty(String name, int value) { if ("number".equals(name)) { this.value1 = value; } } public void setProperty(int ref, String value) { if (0 == ref) { this.value0 = value; } } public void setProperty(int ref, int value) { if (1 == ref) { this.value1 = value; } } } public void test119() throws Exception { JexlEngine jexl = new JexlEngine(); Container quux = new Container("quux", 42); Script get; Object result; Script getName = jexl.createScript("foo.property.name", "foo"); result = getName.execute(null, quux); assertEquals("quux", result); Script get0 = jexl.createScript("foo.property.0", "foo"); result = get0.execute(null, quux); assertEquals("quux", result); Script getNumber = jexl.createScript("foo.property.number", "foo"); result = getNumber.execute(null, quux); assertEquals(42, result); Script get1 = jexl.createScript("foo.property.1", "foo"); result = get1.execute(null, quux); assertEquals(42, result); Script setName = jexl.createScript("foo.property.name = $0", "foo", "$0"); setName.execute(null, quux, "QUUX"); result = getName.execute(null, quux); assertEquals("QUUX", result); result = get0.execute(null, quux); assertEquals("QUUX", result); Script set0 = jexl.createScript("foo.property.0 = $0", "foo", "$0"); set0.execute(null, quux, "BAR"); result = getName.execute(null, quux); assertEquals("BAR", result); result = get0.execute(null, quux); assertEquals("BAR", result); Script setNumber = jexl.createScript("foo.property.number = $0", "foo", "$0"); setNumber.execute(null, quux, -42); result = getNumber.execute(null, quux); assertEquals(-42, result); result = get1.execute(null, quux); assertEquals(-42, result); Script set1 = jexl.createScript("foo.property.1 = $0", "foo", "$0"); set1.execute(null, quux, 24); result = getNumber.execute(null, quux); assertEquals(24, result); result = get1.execute(null, quux); assertEquals(24, result); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/Jexl.java100644 0 0 3271 11673634317 23023 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.Map; /** * Command line interface for Jexl for use in testing * @since 1.0 */ public class Jexl { private Jexl() {} public static void main(String[] args) { final JexlEngine JEXL = new JexlEngine(); Map m = System.getProperties(); // dummy context to get variables JexlContext context = new MapContext(); for(Map.Entry e : m.entrySet()) { context.set(e.getKey().toString(), e.getValue()); } try { for (int i = 0; i < args.length; i++) { Expression e = JEXL.createExpression(args[i]); System.out.println("evaluate(" + args[i] + ") = '" + e.evaluate(context) + "'"); } } catch (Exception e) { e.printStackTrace(); } } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/JexlTest.java100644 0 0 72240 11673634317 23705 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.io.StringReader; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.BitSet; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.jexl2.parser.Parser; /** * Simple testcases * * @since 1.0 */ public class JexlTest extends JexlTestCase { protected static final String METHOD_STRING = "Method string"; protected static final String GET_METHOD_STRING = "GetMethod string"; public JexlTest(String testName) { super(testName); } /** * test a simple property expression */ public void testProperty() throws Exception { /* * tests a simple property expression */ Expression e = JEXL.createExpression("foo.bar"); JexlContext jc = new MapContext(); jc.set("foo", new Foo() ); Object o = e.evaluate(jc); assertTrue("o not instanceof String", o instanceof String); assertEquals("o incorrect", GET_METHOD_STRING, o); } public void testBoolean() throws Exception { JexlContext jc = new MapContext(); jc.set("foo", new Foo() ); jc.set("a", Boolean.TRUE); jc.set("b", Boolean.FALSE); assertExpression(jc, "foo.convertBoolean(a==b)", "Boolean : false"); assertExpression(jc, "foo.convertBoolean(a==true)", "Boolean : true"); assertExpression(jc, "foo.convertBoolean(a==false)", "Boolean : false"); assertExpression(jc, "foo.convertBoolean(true==false)", "Boolean : false"); assertExpression(jc, "true eq false", Boolean.FALSE); assertExpression(jc, "true ne false", Boolean.TRUE); } public void testStringLit() throws Exception { /* * tests a simple property expression */ JexlContext jc = new MapContext(); jc.set("foo", new Foo() ); assertExpression(jc, "foo.get(\"woogie\")", "Repeat : woogie"); } public void testExpression() throws Exception { JexlContext jc = new MapContext(); jc.set("foo", new Foo() ); jc.set("a", Boolean.TRUE); jc.set("b", Boolean.FALSE); jc.set("num", new Integer(5)); jc.set("now", Calendar.getInstance().getTime()); GregorianCalendar gc = new GregorianCalendar(5000, 11, 20); jc.set("now2", gc.getTime()); jc.set("bdec", new BigDecimal("7")); jc.set("bint", new BigInteger("7")); assertExpression(jc, "a == b", Boolean.FALSE); assertExpression(jc, "a==true", Boolean.TRUE); assertExpression(jc, "a==false", Boolean.FALSE); assertExpression(jc, "true==false", Boolean.FALSE); assertExpression(jc, "2 < 3", Boolean.TRUE); assertExpression(jc, "num < 5", Boolean.FALSE); assertExpression(jc, "num < num", Boolean.FALSE); assertExpression(jc, "num < null", Boolean.FALSE); assertExpression(jc, "num < 2.5", Boolean.FALSE); assertExpression(jc, "now2 < now", Boolean.FALSE); // test comparable // assertExpression(jc, "'6' <= '5'", Boolean.FALSE); assertExpression(jc, "num <= 5", Boolean.TRUE); assertExpression(jc, "num <= num", Boolean.TRUE); assertExpression(jc, "num <= null", Boolean.FALSE); assertExpression(jc, "num <= 2.5", Boolean.FALSE); assertExpression(jc, "now2 <= now", Boolean.FALSE); // test comparable // assertExpression(jc, "'6' >= '5'", Boolean.TRUE); assertExpression(jc, "num >= 5", Boolean.TRUE); assertExpression(jc, "num >= num", Boolean.TRUE); assertExpression(jc, "num >= null", Boolean.FALSE); assertExpression(jc, "num >= 2.5", Boolean.TRUE); assertExpression(jc, "now2 >= now", Boolean.TRUE); // test comparable assertExpression(jc, "'6' > '5'", Boolean.TRUE); assertExpression(jc, "num > 4", Boolean.TRUE); assertExpression(jc, "num > num", Boolean.FALSE); assertExpression(jc, "num > null", Boolean.FALSE); assertExpression(jc, "num > 2.5", Boolean.TRUE); assertExpression(jc, "now2 > now", Boolean.TRUE); // test comparable assertExpression(jc, "\"foo\" + \"bar\" == \"foobar\"", Boolean.TRUE); assertExpression(jc, "bdec > num", Boolean.TRUE); assertExpression(jc, "bdec >= num", Boolean.TRUE); assertExpression(jc, "num <= bdec", Boolean.TRUE); assertExpression(jc, "num < bdec", Boolean.TRUE); assertExpression(jc, "bint > num", Boolean.TRUE); assertExpression(jc, "bint == bdec", Boolean.TRUE); assertExpression(jc, "bint >= num", Boolean.TRUE); assertExpression(jc, "num <= bint", Boolean.TRUE); assertExpression(jc, "num < bint", Boolean.TRUE); } public void testEmpty() throws Exception { JexlContext jc = new MapContext(); jc.set("string", ""); jc.set("array", new Object[0]); jc.set("map", new HashMap()); jc.set("list", new ArrayList()); jc.set("set", (new HashMap()).keySet()); jc.set("longstring", "thingthing"); /* * I can't believe anyone thinks this is a syntax.. :) */ assertExpression(jc, "empty nullthing", Boolean.TRUE); assertExpression(jc, "empty string", Boolean.TRUE); assertExpression(jc, "empty array", Boolean.TRUE); assertExpression(jc, "empty map", Boolean.TRUE); assertExpression(jc, "empty set", Boolean.TRUE); assertExpression(jc, "empty list", Boolean.TRUE); assertExpression(jc, "empty longstring", Boolean.FALSE); assertExpression(jc, "not empty longstring", Boolean.TRUE); } public void testSize() throws Exception { JexlContext jc = new MapContext(); jc.set("s", "five!"); jc.set("array", new Object[5]); Map map = new HashMap(); map.put("1", new Integer(1)); map.put("2", new Integer(2)); map.put("3", new Integer(3)); map.put("4", new Integer(4)); map.put("5", new Integer(5)); jc.set("map", map); List list = new ArrayList(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); jc.set("list", list); // 30652 - support for set Set set = new HashSet(); set.addAll(list); set.add("1"); jc.set("set", set); // support generic int size() method BitSet bitset = new BitSet(5); jc.set("bitset", bitset); assertExpression(jc, "size(s)", new Integer(5)); assertExpression(jc, "size(array)", new Integer(5)); assertExpression(jc, "size(list)", new Integer(5)); assertExpression(jc, "size(map)", new Integer(5)); assertExpression(jc, "size(set)", new Integer(5)); assertExpression(jc, "size(bitset)", new Integer(64)); assertExpression(jc, "list.size()", new Integer(5)); assertExpression(jc, "map.size()", new Integer(5)); assertExpression(jc, "set.size()", new Integer(5)); assertExpression(jc, "bitset.size()", new Integer(64)); assertExpression(jc, "list.get(size(list) - 1)", "5"); assertExpression(jc, "list[size(list) - 1]", "5"); assertExpression(jc, "list.get(list.size() - 1)", "5"); } public void testSizeAsProperty() throws Exception { JexlContext jc = new MapContext(); Map map = new HashMap(); map.put("size", "cheese"); jc.set("map", map); jc.set("foo", new Foo()); assertExpression(jc, "map['size']", "cheese"); // PR - unsure whether or not we should support map.size or force usage of the above 'escaped' version // assertExpression(jc, "map.size", "cheese"); assertExpression(jc, "foo.getSize()", new Integer(22)); // failing assertion for size property //assertExpression(jc, "foo.size", new Integer(22)); } /** * test the new function e.g constructor invocation */ public void testNew() throws Exception { JexlContext jc = new MapContext(); jc.set("double", Double.class); jc.set("foo", "org.apache.commons.jexl2.Foo"); Expression expr; Object value; expr = JEXL.createExpression("new(double, 1)"); value = expr.evaluate(jc); assertEquals(expr.toString(), new Double(1.0), value); expr = JEXL.createExpression("new('java.lang.Float', 100)"); value = expr.evaluate(jc); assertEquals(expr.toString(), new Float(100.0), value); expr = JEXL.createExpression("new(foo).quux"); value = expr.evaluate(jc); assertEquals(expr.toString(), "Repeat : quux", value); } /** * test some simple mathematical calculations */ public void testCalculations() throws Exception { JexlContext jc = new MapContext(); /* * test to ensure new string cat works */ jc.set("stringy", "thingy" ); assertExpression(jc, "stringy + 2", "thingy2"); /* * test new null coersion */ jc.set("imanull", null ); assertExpression(jc, "imanull + 2", new Integer(2)); assertExpression(jc, "imanull + imanull", new Integer(0)); /* test for bugzilla 31577 */ jc.set("n", new Integer(0)); assertExpression(jc, "n != null && n != 0", Boolean.FALSE); } /** * test some simple conditions */ public void testConditions() throws Exception { JexlContext jc = new MapContext(); jc.set("foo", new Integer(2) ); jc.set("aFloat", new Float(1)); jc.set("aDouble", new Double(2)); jc.set("aChar", new Character('A')); jc.set("aBool", Boolean.TRUE); StringBuilder buffer = new StringBuilder("abc"); List list = new ArrayList(); List list2 = new LinkedList(); jc.set("aBuffer", buffer); jc.set("aList", list); jc.set("bList", list2); assertExpression(jc, "foo == 2", Boolean.TRUE); assertExpression(jc, "2 == 3", Boolean.FALSE); assertExpression(jc, "3 == foo", Boolean.FALSE); assertExpression(jc, "3 != foo", Boolean.TRUE); assertExpression(jc, "foo != 2", Boolean.FALSE); // test float and double equality assertExpression(jc, "aFloat eq aDouble", Boolean.FALSE); assertExpression(jc, "aFloat ne aDouble", Boolean.TRUE); assertExpression(jc, "aFloat == aDouble", Boolean.FALSE); assertExpression(jc, "aFloat != aDouble", Boolean.TRUE); // test number and character equality assertExpression(jc, "foo == aChar", Boolean.FALSE); assertExpression(jc, "foo != aChar", Boolean.TRUE); // test string and boolean assertExpression(jc, "aBool == 'true'", Boolean.TRUE); assertExpression(jc, "aBool == 'false'", Boolean.FALSE); assertExpression(jc, "aBool != 'false'", Boolean.TRUE); // test null and boolean assertExpression(jc, "aBool == notThere", Boolean.FALSE); assertExpression(jc, "aBool != notThere", Boolean.TRUE); // anything and string as a string comparison assertExpression(jc, "aBuffer == 'abc'", Boolean.TRUE); assertExpression(jc, "aBuffer != 'abc'", Boolean.FALSE); // arbitrary equals assertExpression(jc, "aList == bList", Boolean.TRUE); assertExpression(jc, "aList != bList", Boolean.FALSE); } /** * test some simple conditions */ public void testNotConditions() throws Exception { JexlContext jc = new MapContext(); Foo foo = new Foo(); jc.set("x", Boolean.TRUE ); jc.set("foo", foo ); jc.set("bar", "true" ); assertExpression(jc, "!x", Boolean.FALSE); assertExpression(jc, "x", Boolean.TRUE); assertExpression(jc, "!bar", Boolean.FALSE); assertExpression(jc, "!foo.isSimple()", Boolean.FALSE); assertExpression(jc, "foo.isSimple()", Boolean.TRUE); assertExpression(jc, "!foo.simple", Boolean.FALSE); assertExpression(jc, "foo.simple", Boolean.TRUE); assertExpression(jc, "foo.getCheeseList().size() == 3", Boolean.TRUE); assertExpression(jc, "foo.cheeseList.size() == 3", Boolean.TRUE); jc.set("string", ""); assertExpression(jc, "not empty string", Boolean.FALSE); assertExpression(jc, "not(empty string)", Boolean.FALSE); assertExpression(jc, "not empty(string)", Boolean.FALSE); assertExpression(jc, "! empty string", Boolean.FALSE); assertExpression(jc, "!(empty string)", Boolean.FALSE); assertExpression(jc, "!empty(string)", Boolean.FALSE); } /** * test some simple conditions */ public void testNotConditionsWithDots() throws Exception { JexlContext jc = new MapContext(); jc.set("x.a", Boolean.TRUE ); jc.set("x.b", Boolean.FALSE ); assertExpression(jc, "x.a", Boolean.TRUE); assertExpression(jc, "!x.a", Boolean.FALSE); assertExpression(jc, "!x.b", Boolean.TRUE); } /** * test some simple conditions */ public void testComparisons() throws Exception { JexlContext jc = new MapContext(); jc.set("foo", "the quick and lazy fox" ); assertExpression(jc, "foo.indexOf('quick') > 0", Boolean.TRUE); assertExpression(jc, "foo.indexOf('bar') >= 0", Boolean.FALSE); assertExpression(jc, "foo.indexOf('bar') < 0", Boolean.TRUE); } /** * test some null conditions */ public void testNull() throws Exception { JexlContext jc = new MapContext(); jc.set("bar", new Integer(2) ); assertExpression(jc, "empty foo", Boolean.TRUE); assertExpression(jc, "bar == null", Boolean.FALSE); assertExpression(jc, "foo == null", Boolean.TRUE); assertExpression(jc, "bar != null", Boolean.TRUE); assertExpression(jc, "foo != null", Boolean.FALSE); assertExpression(jc, "empty(bar)", Boolean.FALSE); assertExpression(jc, "empty(foo)", Boolean.TRUE); } /** * test quoting in strings */ public void testStringQuoting() throws Exception { JexlContext jc = new MapContext(); assertExpression(jc, "'\"Hello\"'", "\"Hello\""); assertExpression(jc, "\"I'm testing\"", "I'm testing"); } /** * test some blank strings */ public void testBlankStrings() throws Exception { JexlContext jc = new MapContext(); jc.set("bar", "" ); assertExpression(jc, "foo == ''", Boolean.FALSE); assertExpression(jc, "bar == ''", Boolean.TRUE); assertExpression(jc, "barnotexist == ''", Boolean.FALSE); assertExpression(jc, "empty bar", Boolean.TRUE); assertExpression(jc, "bar.length() == 0", Boolean.TRUE); assertExpression(jc, "size(bar) == 0", Boolean.TRUE); } /** * test some blank strings */ public void testLogicExpressions() throws Exception { JexlContext jc = new MapContext(); jc.set("foo", "abc" ); jc.set("bar", "def" ); assertExpression(jc, "foo == 'abc' || bar == 'abc'", Boolean.TRUE); assertExpression(jc, "foo == 'abc' or bar == 'abc'", Boolean.TRUE); assertExpression(jc, "foo == 'abc' && bar == 'abc'", Boolean.FALSE); assertExpression(jc, "foo == 'abc' and bar == 'abc'", Boolean.FALSE); assertExpression(jc, "foo == 'def' || bar == 'abc'", Boolean.FALSE); assertExpression(jc, "foo == 'def' or bar == 'abc'", Boolean.FALSE); assertExpression(jc, "foo == 'abc' && bar == 'def'", Boolean.TRUE); assertExpression(jc, "foo == 'abc' and bar == 'def'", Boolean.TRUE); } /** * test variables with underscore names */ public void testVariableNames() throws Exception { JexlContext jc = new MapContext(); jc.set("foo_bar", "123" ); assertExpression(jc, "foo_bar", "123"); } /** * test the use of dot notation to lookup map entries */ public void testMapDot() throws Exception { Map foo = new HashMap(); foo.put( "bar", "123" ); JexlContext jc = new MapContext(); jc.set("foo", foo ); assertExpression(jc, "foo.bar", "123"); } /** * Tests string literals */ public void testStringLiterals() throws Exception { JexlContext jc = new MapContext(); jc.set("foo", "bar" ); assertExpression(jc, "foo == \"bar\"", Boolean.TRUE); assertExpression(jc, "foo == 'bar'", Boolean.TRUE); } /** * test the use of an int based property */ public void testIntProperty() throws Exception { Foo foo = new Foo(); // lets check the square function first.. assertEquals(4, foo.square(2)); assertEquals(4, foo.square(-2)); JexlContext jc = new MapContext(); jc.set("foo", foo ); assertExpression(jc, "foo.count", new Integer(5)); assertExpression(jc, "foo.square(2)", new Integer(4)); assertExpression(jc, "foo.square(-2)", new Integer(4)); } /** * test the -1 comparison bug */ public void testNegativeIntComparison() throws Exception { JexlContext jc = new MapContext(); Foo foo = new Foo(); jc.set("foo", foo ); assertExpression(jc, "foo.count != -1", Boolean.TRUE); assertExpression(jc, "foo.count == 5", Boolean.TRUE); assertExpression(jc, "foo.count == -1", Boolean.FALSE); } /** * Attempts to recreate bug http://jira.werken.com/ViewIssue.jspa?key=JELLY-8 */ public void testCharAtBug() throws Exception { JexlContext jc = new MapContext(); jc.set("foo", "abcdef"); assertExpression(jc, "foo.substring(2,4)", "cd"); assertExpression(jc, "foo.charAt(2)", new Character('c')); assertExpression(jc, "foo.charAt(-2)", null); } public void testEmptyDottedVariableName() throws Exception { JexlContext jc = new MapContext(); jc.set( "this.is.a.test", ""); assertExpression(jc, "empty(this.is.a.test)", Boolean.TRUE); } public void testEmptySubListOfMap() throws Exception { JexlContext jc = new MapContext(); Map> m = new HashMap>(); m.put("aList", new ArrayList()); jc.set( "aMap", m ); assertExpression( jc, "empty( aMap.aList )", Boolean.TRUE ); } public void testCoercionWithComparisionOperators() throws Exception { JexlContext jc = new MapContext(); assertExpression(jc, "'2' > 1", Boolean.TRUE); assertExpression(jc, "'2' >= 1", Boolean.TRUE); assertExpression(jc, "'2' >= 2", Boolean.TRUE); assertExpression(jc, "'2' < 1", Boolean.FALSE); assertExpression(jc, "'2' <= 1", Boolean.FALSE); assertExpression(jc, "'2' <= 2", Boolean.TRUE); assertExpression(jc, "2 > '1'", Boolean.TRUE); assertExpression(jc, "2 >= '1'", Boolean.TRUE); assertExpression(jc, "2 >= '2'", Boolean.TRUE); assertExpression(jc, "2 < '1'", Boolean.FALSE); assertExpression(jc, "2 <= '1'", Boolean.FALSE); assertExpression(jc, "2 <= '2'", Boolean.TRUE); } /** * Test that 'and' only evaluates the second item if needed * @throws Exception if there are errors */ public void testBooleanShortCircuitAnd() throws Exception { // handle false for the left arg of 'and' Foo tester = new Foo(); JexlContext jc = new MapContext(); jc.set("first", Boolean.FALSE); jc.set("foo", tester); Expression expr = JEXL.createExpression("first and foo.trueAndModify"); expr.evaluate(jc); assertTrue("Short circuit failure: rhs evaluated when lhs FALSE", !tester.getModified()); // handle true for the left arg of 'and' tester = new Foo(); jc.set("first", Boolean.TRUE); jc.set("foo", tester); expr.evaluate(jc); assertTrue("Short circuit failure: rhs not evaluated when lhs TRUE", tester.getModified()); } /** * Test that 'or' only evaluates the second item if needed * @throws Exception if there are errors */ public void testBooleanShortCircuitOr() throws Exception { // handle false for the left arg of 'or' Foo tester = new Foo(); JexlContext jc = new MapContext(); jc.set("first", Boolean.FALSE); jc.set("foo", tester); Expression expr = JEXL.createExpression("first or foo.trueAndModify"); expr.evaluate(jc); assertTrue("Short circuit failure: rhs not evaluated when lhs FALSE", tester.getModified()); // handle true for the left arg of 'or' tester = new Foo(); jc.set("first", Boolean.TRUE); jc.set("foo", tester); expr.evaluate(jc); assertTrue("Short circuit failure: rhs evaluated when lhs TRUE", !tester.getModified()); } /** * Simple test of '+' as a string concatenation operator * @throws Exception */ public void testStringConcatenation() throws Exception { JexlContext jc = new MapContext(); jc.set("first", "Hello"); jc.set("second", "World"); assertExpression(jc, "first + ' ' + second", "Hello World"); } public void testToString() throws Exception { String code = "abcd"; Expression expr = JEXL.createExpression(code); assertEquals("Bad expression value", code, expr.toString()); } /** * Make sure bad syntax throws ParseException * @throws Exception on errors */ public void testBadParse() throws Exception { try { assertExpression(new MapContext(), "empty()", null); fail("Bad expression didn't throw ParseException"); } catch (JexlException pe) { // expected behaviour } } /** * Test the ## comment in a string * @throws Exception */ public void testComment() throws Exception { assertExpression(new MapContext(), "## double or nothing\n 1 + 1", Integer.valueOf("2")); } /** * Test assignment. * @throws Exception */ public void testAssignment() throws Exception { JexlContext jc = new MapContext(); jc.set("aString", "Hello"); Foo foo = new Foo(); jc.set("foo", foo); Parser parser = new Parser(new StringReader(";")); parser.parse(new StringReader("aString = 'World';"), null); assertExpression(jc, "hello = 'world'", "world"); assertEquals("hello variable not changed", "world", jc.get("hello")); assertExpression(jc, "result = 1 + 1", new Integer(2)); assertEquals("result variable not changed", new Integer(2), jc.get("result")); // todo: make sure properties can be assigned to, fall back to flat var if no property // assertExpression(jc, "foo.property1 = '99'", "99"); // assertEquals("property not set", "99", foo.getProperty1()); } public void testAntPropertiesWithMethods() throws Exception { JexlContext jc = new MapContext(); String value = "Stinky Cheese"; jc.set("maven.bob.food", value); assertExpression(jc, "maven.bob.food.length()", new Integer(value.length())); assertExpression(jc, "empty(maven.bob.food)", Boolean.FALSE); assertExpression(jc, "size(maven.bob.food)", new Integer(value.length())); assertExpression(jc, "maven.bob.food + ' is good'", value + " is good"); // DG: Note the following ant properties don't work // String version = "1.0.3"; // jc.set("commons-logging", version); // assertExpression(jc, "commons-logging", version); } public void testUnicodeSupport() throws Exception { JexlContext jc = new MapContext(); assertExpression(jc, "myvar == 'Użytkownik'", Boolean.FALSE); assertExpression(jc, "'c:\\some\\windows\\path'", "c:\\some\\windows\\path"); assertExpression(jc, "'foo\\u0020bar'", "foo\u0020bar"); assertExpression(jc, "'foo\\u0020\\u0020bar'", "foo\u0020\u0020bar"); assertExpression(jc, "'\\u0020foobar\\u0020'", "\u0020foobar\u0020"); } public static final class Duck { int user = 10; @SuppressWarnings("boxing") public Integer get(String val) { if ("zero".equals(val)) return 0; if ("one".equals(val)) return 1; if ("user".equals(val)) return user; return -1; } @SuppressWarnings("boxing") public void set(String val, Object value) { if ("user".equals(val)) { if ("zero".equals(value)) user = 0; else if ("one".equals(value)) user = 1; else user = value instanceof Integer? (Integer) value : -1; } } } @SuppressWarnings("boxing") public void testDuck() throws Exception { JexlEngine jexl = JEXL; JexlContext jc = new MapContext(); jc.set("duck", new Duck()); Expression expr; Object result; expr = jexl.createExpression("duck.zero"); result = expr.evaluate(jc); assertEquals(expr.toString(), 0, result); expr = jexl.createExpression("duck.one"); result = expr.evaluate(jc); assertEquals(expr.toString(), 1, result); expr = jexl.createExpression("duck.user = 20"); result = expr.evaluate(jc); assertEquals(expr.toString(), 20, result); expr = jexl.createExpression("duck.user"); result = expr.evaluate(jc); assertEquals(expr.toString(), 20, result); expr = jexl.createExpression("duck.user = 'zero'"); result = expr.evaluate(jc); expr = jexl.createExpression("duck.user"); result = expr.evaluate(jc); assertEquals(expr.toString(), 0, result); } @SuppressWarnings("boxing") public void testArray() throws Exception { int[] array = { 100, 101 , 102 }; JexlEngine jexl = JEXL; JexlContext jc = new MapContext(); jc.set("array", array); Expression expr; Object result; expr = jexl.createExpression("array.1"); result = expr.evaluate(jc); assertEquals(expr.toString(), 101, result); expr = jexl.createExpression("array[1] = 1010"); result = expr.evaluate(jc); assertEquals(expr.toString(), 1010, result); expr = jexl.createExpression("array.0"); result = expr.evaluate(jc); assertEquals(expr.toString(), 100, result); } /** * Asserts that the given expression returns the given value when applied to the * given context */ protected void assertExpression(JexlContext jc, String expression, Object expected) throws Exception { Expression e = JEXL.createExpression(expression); Object actual = e.evaluate(jc); assertEquals(expression, expected, actual); } }commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/JexlTestCase.java100644 0 0 23555 11673634321 24501 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Iterator; import java.util.Map; import java.util.List; import java.util.ArrayList; import org.apache.commons.jexl2.parser.JexlNode; import org.apache.commons.jexl2.parser.ASTJexlScript; import junit.framework.TestCase; /** * Implements runTest methods to dynamically instantiate and invoke a test, * wrapping the call with setUp(), tearDown() calls. * Eases the implementation of main methods to debug. */ public class JexlTestCase extends TestCase { /** No parameters signature for test run. */ private static final Class[] noParms = {}; /** String parameter signature for test run. */ private static final Class[] stringParm = {String.class}; /** A default Jexl engine instance. */ protected final JexlEngine JEXL; public JexlTestCase(String name) { this(name, new JexlEngine()); } protected JexlTestCase(String name, JexlEngine jexl) { super(name); JEXL = jexl; JEXL.setCache(512); } public JexlTestCase() { this(new JexlEngine()); } protected JexlTestCase(JexlEngine jexl) { super(); JEXL = jexl; JEXL.setCache(512); } @Override protected void tearDown() throws Exception { debuggerCheck(JEXL); } public static JexlEngine createEngine(boolean lenient) { return new JexlEngine(null, new JexlArithmetic(lenient), null, null); } public static JexlEngine createThreadedArithmeticEngine(boolean lenient) { return new JexlEngine(null, new JexlThreadedArithmetic(lenient), null, null); } /** * Will force testing the debugger for each derived test class by * recreating each expression from the JexlNode in the JexlEngine cache & * testing them for equality with the origin. * @throws Exception */ public static void debuggerCheck(JexlEngine jexl) throws Exception { // without a cache, nothing to check if (jexl.cache == null) { return; } JexlEngine jdbg = new JexlEngine(); jdbg.parser.ALLOW_REGISTERS = true; Debugger dbg = new Debugger(); // iterate over all expression in cache Iterator> inodes = jexl.cache.entrySet().iterator(); while (inodes.hasNext()) { Map.Entry entry = inodes.next(); JexlNode node = entry.getValue(); // recreate expr string from AST dbg.debug(node); String expressiondbg = dbg.data(); // recreate expr from string Script exprdbg = jdbg.createScript(expressiondbg); // make arg cause become the root cause JexlNode root = ((ExpressionImpl) exprdbg).script; while (root.jjtGetParent() != null) { root = root.jjtGetParent(); } // test equality String reason = JexlTestCase.checkEquals(root, node); if (reason != null) { throw new RuntimeException("debugger equal failed: " + expressiondbg +" /**** " +reason+" **** */ " + entry.getKey()); } } } /** * Creates a list of all descendants of a script including itself. * @param script the script to flatten * @return the descendants-and-self list */ protected static ArrayList flatten(JexlNode node) { ArrayList list = new ArrayList(); flatten(list, node); return list; } /** * Recursively adds all children of a script to the list of descendants. * @param list the list of descendants to add to * @param script the script & descendants to add */ private static void flatten(List list, JexlNode node) { int nc = node.jjtGetNumChildren(); list.add(node); for(int c = 0; c < nc; ++c) { flatten(list, node.jjtGetChild(c)); } } /** * Checks the equality of 2 nodes by comparing all their descendants. * Descendants must have the same class and same image if non null. * @param lhs the left script * @param rhs the right script * @return null if true, a reason otherwise */ private static String checkEquals(JexlNode lhs, JexlNode rhs) { if (lhs != rhs) { ArrayList lhsl = flatten(lhs); ArrayList rhsl = flatten(rhs); if (lhsl.size() != rhsl.size()) { return "size: " + lhsl.size() + " != " + rhsl.size(); } for(int n = 0; n < lhsl.size(); ++n) { lhs = lhsl.get(n); rhs = rhsl.get(n); if (lhs.getClass() != rhs.getClass()) { return "class: " + lhs.getClass() + " != " + rhs.getClass(); } if ((lhs.image == null && rhs.image != null) || (lhs.image != null && rhs.image == null)) { return "image: " + lhs.image + " != " + rhs.image; } if (lhs.image != null && !lhs.image.equals(rhs.image)) { return "image: " + lhs.image + " != " + rhs.image; } } } return null; } /** * A helper class to help debug AST problems. * @param e the script * @return an indented version of the AST */ protected String flattenedStr(Script e) { return e.getText() + "\n" + flattenedStr(((ExpressionImpl) e).script); } static private String indent(JexlNode node) { StringBuilder strb = new StringBuilder(); while (node != null) { strb.append(" "); node = node.jjtGetParent(); } return strb.toString(); } private String flattenedStr(JexlNode node) { ArrayList flattened = flatten(node); StringBuilder strb = new StringBuilder(); for (JexlNode flat : flattened) { strb.append(indent(flat)); strb.append(flat.getClass().getSimpleName()); if (flat.image != null) { strb.append(" = "); strb.append(flat.image); } strb.append("\n"); } return strb.toString(); } /** * Dynamically runs a test method. * @param name the test method to run * @throws Exception if anything goes wrong */ public void runTest(String name) throws Exception { if ("runTest".equals(name)) { return; } Method method = null; try { method = this.getClass().getDeclaredMethod(name, noParms); } catch(Exception xany) { fail("no such test: " + name); return; } try { this.setUp(); method.invoke(this); } finally { this.tearDown(); } } /** * Instantiate and runs a test method; useful for debugging purpose. * For instance: * * public static void main(String[] args) throws Exception { * runTest("BitwiseOperatorTest","testAndVariableNumberCoercion"); * } * * @param tname the test class name * @param mname the test class method * @throws Exception */ public static void runTest(String tname, String mname) throws Exception { String testClassName = "org.apache.commons.jexl2."+tname; Class clazz = null; JexlTestCase test = null; // find the class try { clazz = (Class) Class.forName(testClassName); } catch(ClassNotFoundException xclass) { fail("no such class: " + testClassName); return; } // find ctor & instantiate Constructor ctor = null; try { ctor = clazz.getConstructor(stringParm); test = ctor.newInstance("debug"); } catch(NoSuchMethodException xctor) { // instantiate default class ctor try { test = clazz.newInstance(); } catch(Exception xany) { fail("cant instantiate test: " + xany); return; } } catch(Exception xany) { fail("cant instantiate test: " + xany); return; } // Run the test test.runTest(mname); } /** * Runs a test. * @param args where args[0] is the test class name and args[1] the test class method * @throws Exception */ public static void main(String[] args) throws Exception { runTest(args[0], args[1]); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/junit/Asserter.java100644 0 0 12371 11673634317 25063 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.junit; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; import junit.framework.Assert; import org.apache.commons.jexl2.Expression; import org.apache.commons.jexl2.JexlArithmetic; import org.apache.commons.jexl2.JexlContext; import org.apache.commons.jexl2.MapContext; import org.apache.commons.jexl2.JexlEngine; import org.apache.commons.jexl2.JexlException; import org.apache.commons.jexl2.JexlThreadedArithmetic; /** * A utility class for performing JUnit based assertions using Jexl * expressions. This class can make it easier to do unit tests using * Jexl navigation expressions. * * @since 1.0 */ public class Asserter extends Assert { /** variables used during asserts. */ private final Map variables = new HashMap(); /** context to use during asserts. */ private final JexlContext context = new MapContext(variables); /** Jexl engine to use during Asserts. */ private final JexlEngine engine; /** * * Create an asserter. * @param jexl the JEXL engine to use */ public Asserter(JexlEngine jexl) { engine = jexl; } /** * Retrieves the underlying JEXL engine. * @return the JEXL engine */ public JexlEngine getEngine() { return engine; } /** * Retrieves the underlying JEXL context. * @return the JEXL context */ public JexlContext getContext() { return context; } /** * Performs an assertion that the value of the given Jexl expression * evaluates to the given expected value. * * @param expression is the Jexl expression to evaluate * @param expected is the expected value of the expression * @throws Exception if the expression could not be evaluationed or an assertion * fails */ public void assertExpression(String expression, Object expected) throws Exception { Expression exp = engine.createExpression(expression); Object value = exp.evaluate(context); if (expected instanceof BigDecimal) { JexlArithmetic jexla = engine.getArithmetic(); assertTrue("expression: " + expression, ((BigDecimal) expected).compareTo(jexla.toBigDecimal(value)) == 0); } else { assertEquals("expression: " + expression, expected, value); } } /** * Performs an assertion that the expression fails throwing an exception. * If matchException is not null, the exception message is expected to match it as a regexp. * The engine is temporarily switched to strict * verbose to maximize error detection abilities. * @param expression the expression that should fail * @param matchException the exception message pattern * @throws Exception if the expression did not fail or the exception did not match the expected pattern */ public void failExpression(String expression, String matchException) throws Exception { boolean[] flags = {engine.isLenient(), engine.isSilent()}; try { if (engine.getArithmetic() instanceof JexlThreadedArithmetic) { engine.setLenient(false); } engine.setSilent(false); Expression exp = engine.createExpression(expression); exp.evaluate(context); fail("expression: " + expression); } catch (JexlException xjexl) { if (matchException != null && !xjexl.getMessage().matches(matchException)) { fail("expression: " + expression + ", expected: " + matchException + ", got " + xjexl.getMessage()); } } finally { if (engine.getArithmetic() instanceof JexlThreadedArithmetic) { engine.setLenient(flags[0]); } engine.setSilent(flags[1]); } } /** * Puts a variable of a certain name in the context so that it can be used from * assertion expressions. * * @param name variable name * @param value variable value */ public void setVariable(String name, Object value) { variables.put(name, value); } /** * Removes a variable of a certain name from the context. * @param name variable name * @return variable value */ public Object removeVariable(String name) { return variables.remove(name); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/junit/AsserterTest.java100644 0 0 5056 11673634317 25705 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id: AsserterTest.java 1125721 2011-05-21 14:53:18Z henrib $ */ package org.apache.commons.jexl2.junit; import junit.framework.AssertionFailedError; import org.apache.commons.jexl2.JexlEngine; import org.apache.commons.jexl2.JexlTestCase; import org.apache.commons.jexl2.Foo; /** * Simple testcases * * @since 1.0 */ public class AsserterTest extends JexlTestCase { public AsserterTest(String testName) { super(testName); } public void testThis() throws Exception { Asserter asserter = new Asserter(JEXL); asserter.setVariable("this", new Foo()); asserter.assertExpression("this.get('abc')", "Repeat : abc"); try { asserter.assertExpression("this.count", "Wrong Value"); fail("This method should have thrown an assertion exception"); } catch (AssertionFailedError e) { // it worked! } } public void testVariable() throws Exception { JexlEngine jexl = new JexlEngine(); jexl.setSilent(true); Asserter asserter = new Asserter(jexl); asserter.setVariable("foo", new Foo()); asserter.setVariable("person", "James"); asserter.assertExpression("person", "James"); asserter.assertExpression("size(person)", new Integer(5)); asserter.assertExpression("foo.getCount()", new Integer(5)); asserter.assertExpression("foo.count", new Integer(5)); try { asserter.assertExpression("bar.count", new Integer(5)); fail("This method should have thrown an assertion exception"); } catch (AssertionFailedError e) { // it worked! } } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/junit/package.html100644 0 0 3761 11673634317 24674 0ustar 0 0 Package Documentation for org.apache.commons.jexl2.junit Package Using JEXL expressions in JUnit assertions.

Introduction

This package only contains one class, Asserter, which allows you to use a JEXL expression in a JUnit assertion. The following example demonstrates the use of the Asserter class. An instance is created, and the internal JexlContext is populated via calls to setVariable(). Calls to assertExpression() succeed if the expression evaluates to the value of the second parameter, otherwise an AssertionFailedException is thrown.

   Asserter asserter = new Asserter();
   asserter.setVariable("foo", new Foo());
   asserter.setVariable("person", "James");

   asserter.assertExpression("person", "James");
   asserter.assertExpression("size(person)", new Integer(5));
        
   asserter.assertExpression("foo.getCount()", new Integer(5));
   asserter.assertExpression("foo.count", new Integer(5));
  
commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/MapLiteralTest.java100644 0 0 11601 11673634320 25021 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * Tests for map literals * * @since 1.2 */ public class MapLiteralTest extends JexlTestCase { public void testLiteralWithStrings() throws Exception { Expression e = JEXL.createExpression( "{ 'foo' : 'bar' }" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); assertEquals( Collections.singletonMap( "foo", "bar" ), o ); } public void testLiteralWithMultipleEntries() throws Exception { Expression e = JEXL.createExpression( "{ 'foo' : 'bar', 'eat' : 'food' }" ); JexlContext jc = new MapContext(); Map expected = new HashMap(); expected.put( "foo", "bar" ); expected.put( "eat", "food" ); Object o = e.evaluate( jc ); assertEquals( expected, o ); } public void testLiteralWithNumbers() throws Exception { Expression e = JEXL.createExpression( "{ 5 : 10 }" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); assertEquals( Collections.singletonMap( new Integer( 5 ), new Integer( 10 ) ), o ); e = JEXL.createExpression("m = { 3 : 30, 4 : 40, 5 : 'fifty', '7' : 'seven', 7 : 'SEVEN' }"); e.evaluate(jc); e = JEXL.createExpression("m.3"); o = e.evaluate(jc); assertEquals(new Integer(30), o); e = JEXL.createExpression("m[4]"); o = e.evaluate(jc); assertEquals(new Integer(40), o); jc.set("i", Integer.valueOf(5)); e = JEXL.createExpression("m[i]"); o = e.evaluate(jc); assertEquals("fifty", o); e = JEXL.createExpression("m.3 = 'thirty'"); e.evaluate(jc); e = JEXL.createExpression("m.3"); o = e.evaluate(jc); assertEquals("thirty", o); e = JEXL.createExpression("m['7']"); o = e.evaluate(jc); assertEquals("seven", o); e = JEXL.createExpression("m.7"); o = e.evaluate(jc); assertEquals("SEVEN", o); jc.set("k", Integer.valueOf(7)); e = JEXL.createExpression("m[k]"); o = e.evaluate(jc); assertEquals("SEVEN", o); jc.set("k", "7"); e = JEXL.createExpression("m[k]"); o = e.evaluate(jc); assertEquals("seven", o); } public void testSizeOfSimpleMapLiteral() throws Exception { Expression e = JEXL.createExpression( "size({ 'foo' : 'bar' })" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); assertEquals( new Integer( 1 ), o ); } public void testCallingMethodsOnNewMapLiteral() throws Exception { Expression e = JEXL.createExpression( "size({ 'foo' : 'bar' }.values())" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); assertEquals( new Integer( 1 ), o ); } public void testNotEmptySimpleMapLiteral() throws Exception { Expression e = JEXL.createExpression( "empty({ 'foo' : 'bar' })" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); assertFalse( ( (Boolean) o ).booleanValue() ); } public void testMapMapLiteral() throws Exception { Expression e = JEXL.createExpression( "{'foo' : { 'inner' : 'bar' }}" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); assertNotNull(o); jc.set("outer", o); e = JEXL.createExpression("outer.foo.inner"); o = e.evaluate( jc ); assertEquals( "bar", o ); } public void testMapArrayLiteral() throws Exception { Expression e = JEXL.createExpression( "{'foo' : [ 'inner' , 'bar' ]}" ); JexlContext jc = new MapContext(); Object o = e.evaluate( jc ); assertNotNull(o); jc.set("outer", o); e = JEXL.createExpression("outer.foo.1"); o = e.evaluate( jc ); assertEquals( "bar", o ); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/MethodTest.java100644 0 0 32300 11673634320 24206 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.HashMap; import java.util.Map; import org.apache.commons.jexl2.introspection.JexlMethod; import org.apache.commons.jexl2.junit.Asserter; /** * Tests for calling methods on objects * * @since 2.0 */ public class MethodTest extends JexlTestCase { private Asserter asserter; private static final String METHOD_STRING = "Method string"; public static class VarArgs { public String callInts(Integer... args) { int result = 0; if (args != null) { for (int i = 0; i < args.length; i++) { result += args[i] != null ? args[i].intValue() : -100; } } else { result = -1000; } return "Varargs:" + result; } public String callMixed(Integer fixed, Integer... args) { int result = fixed.intValue(); if (args != null) { for (int i = 0; i < args.length; i++) { result += args[i] != null ? args[i].intValue() : -100; } } else { result -= 1000; } return "Mixed:" + result; } public String callMixed(String mixed, Integer... args) { int result = 0; if (args != null) { for (int i = 0; i < args.length; i++) { result += args[i] != null ? args[i].intValue() : -100; } } else { result = -1000; } return mixed + ":" + result; } public String concat(String... strs) { if (strs.length > 0) { StringBuilder strb = new StringBuilder(strs[0]); for(int s = 1; s < strs.length; ++s) { strb.append(", "); strb.append(strs[s]); } return strb.toString(); } else { return ""; } } } public static class Functor { public int ten() { return 10; } public int plus10(int num) { return num + 10; } public static int TWENTY() { return 20; } public static int PLUS20(int num) { return num + 20; } public static Class NPEIfNull(Object x) { return x.getClass(); } } public static class EnhancedContext extends MapContext { int factor = 6; } public static class ContextualFunctor { private final EnhancedContext context; public ContextualFunctor(EnhancedContext theContext) { context = theContext; } public int ratio(int n) { context.factor -= 1; return n / context.factor; } } @Override public void setUp() { asserter = new Asserter(JEXL); } public void testCallVarArgMethod() throws Exception { VarArgs test = new VarArgs(); asserter.setVariable("test", test); asserter.assertExpression("test.callInts()", "Varargs:0"); asserter.assertExpression("test.callInts(1)", "Varargs:1"); asserter.assertExpression("test.callInts(1,2,3,4,5)", "Varargs:15"); asserter.assertExpression("test.concat(['1', '2', '3'])", "1, 2, 3"); asserter.assertExpression("test.concat('1', '2', '3')", "1, 2, 3"); } public void testCallMixedVarArgMethod() throws Exception { VarArgs test = new VarArgs(); asserter.setVariable("test", test); assertEquals("Mixed:1", test.callMixed(Integer.valueOf(1))); asserter.assertExpression("test.callMixed(1)", "Mixed:1"); // Java and JEXL equivalent behavior: 'Mixed:-999' expected //{ assertEquals("Mixed:-999", test.callMixed(Integer.valueOf(1), (Integer[]) null)); asserter.assertExpression("test.callMixed(1, null)", "Mixed:-999"); //} asserter.assertExpression("test.callMixed(1,2)", "Mixed:3"); asserter.assertExpression("test.callMixed(1,2,3,4,5)", "Mixed:15"); } public void testCallJexlVarArgMethod() throws Exception { VarArgs test = new VarArgs(); asserter.setVariable("test", test); assertEquals("jexl:0", test.callMixed("jexl")); asserter.assertExpression("test.callMixed('jexl')", "jexl:0"); // Java and JEXL equivalent behavior: 'jexl:-1000' expected //{ assertEquals("jexl:-1000", test.callMixed("jexl", (Integer[]) null)); asserter.assertExpression("test.callMixed('jexl', null)", "jexl:-1000"); //} asserter.assertExpression("test.callMixed('jexl', 2)", "jexl:2"); asserter.assertExpression("test.callMixed('jexl',2,3,4,5)", "jexl:14"); } public void testInvoke() throws Exception { Functor func = new Functor(); assertEquals(Integer.valueOf(10), JEXL.invokeMethod(func, "ten")); assertEquals(Integer.valueOf(42), JEXL.invokeMethod(func, "PLUS20", Integer.valueOf(22))); try { JEXL.invokeMethod(func, "nonExistentMethod"); fail("method does not exist!"); } catch (Exception xj0) { // ignore } try { JEXL.invokeMethod(func, "NPEIfNull", (Object[]) null); fail("method should have thrown!"); } catch (Exception xj0) { // ignore } } /** * test a simple method expression */ public void testMethod() throws Exception { // tests a simple method expression asserter.setVariable("foo", new Foo()); asserter.assertExpression("foo.bar()", METHOD_STRING); } public void testMulti() throws Exception { asserter.setVariable("foo", new Foo()); asserter.assertExpression("foo.innerFoo.bar()", METHOD_STRING); } /** * test some String method calls */ public void testStringMethods() throws Exception { asserter.setVariable("foo", "abcdef"); asserter.assertExpression("foo.substring(3)", "def"); asserter.assertExpression("foo.substring(0,(size(foo)-3))", "abc"); asserter.assertExpression("foo.substring(0,size(foo)-3)", "abc"); asserter.assertExpression("foo.substring(0,foo.length()-3)", "abc"); asserter.assertExpression("foo.substring(0, 1+1)", "ab"); } /** * Ensures static methods on objects can be called. */ public void testStaticMethodInvocation() throws Exception { asserter.setVariable("aBool", Boolean.FALSE); asserter.assertExpression("aBool.valueOf('true')", Boolean.TRUE); } public void testStaticMethodInvocationOnClasses() throws Exception { asserter.setVariable("Boolean", Boolean.class); asserter.assertExpression("Boolean.valueOf('true')", Boolean.TRUE); } public static class MyMath { public double cos(double x) { return Math.cos(x); } } public void testTopLevelCall() throws Exception { java.util.Map funcs = new java.util.HashMap(); funcs.put(null, new Functor()); funcs.put("math", new MyMath()); funcs.put("cx", ContextualFunctor.class); JEXL.setFunctions(funcs); JexlContext jc = new EnhancedContext(); Expression e = JEXL.createExpression("ten()"); Object o = e.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); e = JEXL.createExpression("plus10(10)"); o = e.evaluate(jc); assertEquals("Result is not 20", new Integer(20), o); e = JEXL.createExpression("plus10(ten())"); o = e.evaluate(jc); assertEquals("Result is not 20", new Integer(20), o); jc.set("pi", new Double(Math.PI)); e = JEXL.createExpression("math:cos(pi)"); o = e.evaluate(jc); assertEquals(Double.valueOf(-1), o); e = JEXL.createExpression("cx:ratio(10) + cx:ratio(20)"); o = e.evaluate(jc); assertEquals(Integer.valueOf(7), o); } public void testNamespaceCall() throws Exception { java.util.Map funcs = new java.util.HashMap(); funcs.put("func", new Functor()); funcs.put("FUNC", Functor.class); JEXL.setFunctions(funcs); Expression e = JEXL.createExpression("func:ten()"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertEquals("Result is not 10", new Integer(10), o); e = JEXL.createExpression("func:plus10(10)"); jc = new MapContext(); o = e.evaluate(jc); assertEquals("Result is not 20", new Integer(20), o); e = JEXL.createExpression("func:plus10(func:ten())"); jc = new MapContext(); o = e.evaluate(jc); assertEquals("Result is not 20", new Integer(20), o); e = JEXL.createExpression("FUNC:PLUS20(10)"); jc = new MapContext(); o = e.evaluate(jc); assertEquals("Result is not 30", new Integer(30), o); e = JEXL.createExpression("FUNC:PLUS20(FUNC:TWENTY())"); jc = new MapContext(); o = e.evaluate(jc); assertEquals("Result is not 40", new Integer(40), o); } public static class ScriptContext extends MapContext implements NamespaceResolver { Map nsScript; ScriptContext(Map ns) { nsScript = ns; } public Object resolveNamespace(String name) { if (name == null) { return this; } if ("script".equals(name)) { return nsScript; } return null; } } public void testScriptCall() throws Exception { JexlContext context = new MapContext(); Script plus = JEXL.createScript("a + b", new String[]{"a", "b"}); context.set("plus", plus); Script forty2 = JEXL.createScript("plus(4, 2) * plus(4, 3)"); Object o = forty2.execute(context); assertEquals("Result is not 42", new Integer(42), o); Map foo = new HashMap(); foo.put("plus", plus); context.set("foo", foo); forty2 = JEXL.createScript("foo.plus(4, 2) * foo.plus(4, 3)"); o = forty2.execute(context); assertEquals("Result is not 42", new Integer(42), o); context = new ScriptContext(foo); forty2 = JEXL.createScript("script:plus(4, 2) * script:plus(4, 3)"); o = forty2.execute(context); assertEquals("Result is not 42", new Integer(42), o); final JexlArithmetic ja = JEXL.getArithmetic(); JexlMethod mplus = new JexlMethod() { public Object invoke(Object obj, Object[] params) throws Exception { if (obj instanceof Map) { return ja.add(params[0], params[1]); } else { throw new Exception("not a script context"); } } public Object tryInvoke(String name, Object obj, Object[] params) { try { if ("plus".equals(name)) { return invoke(obj, params); } } catch (Exception xany) { // ignore and fail by returning this } return this; } public boolean tryFailed(Object rval) { // this is the marker for failure return rval == this; } public boolean isCacheable() { return true; } public Class getReturnType() { return Object.class; } }; foo.put("PLUS", mplus); forty2 = JEXL.createScript("script:PLUS(4, 2) * script:PLUS(4, 3)"); o = forty2.execute(context); assertEquals("Result is not 42", new Integer(42), o); context.set("foo.bar", foo); forty2 = JEXL.createScript("foo.'bar'.PLUS(4, 2) * foo.bar.PLUS(4, 3)"); o = forty2.execute(context); assertEquals("Result is not 42", new Integer(42), o); } }commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/ParseFailuresTest.java100644 0 0 7157 11673634317 25535 0ustar 0 0 /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Tests for malformed expressions and scripts. * ({@link org.apache.commons.jexl2.JexlEngine#createExpression(String)} and * {@link org.apache.commons.jexl2.JexlEngine#createScript(String)} should throw * {@link org.apache.commons.jexl2.JexlException}s). * * @since 1.1 */ public class ParseFailuresTest extends JexlTestCase { /** * Create the test. * * @param testName name of the test */ public ParseFailuresTest(String testName) { super(testName); JEXL.setSilent(false); } public void testMalformedExpression1() throws Exception { // this will throw a JexlException String badExpression = "eq"; try { JEXL.createExpression(badExpression); fail("Parsing \"" + badExpression + "\" should result in a JexlException"); } catch (JexlException pe) { // expected JEXL.logger.error(pe); } } public void testMalformedExpression2() throws Exception { // this will throw a TokenMgrErr, which we rethrow as a JexlException String badExpression = "?"; try { JEXL.createExpression(badExpression); fail("Parsing \"" + badExpression + "\" should result in a JexlException"); } catch (JexlException pe) { // expected JEXL.logger.error(pe); } } public void testMalformedScript1() throws Exception { // this will throw a TokenMgrErr, which we rethrow as a JexlException String badScript = "eq"; try { JEXL.createScript(badScript); fail("Parsing \"" + badScript + "\" should result in a JexlException"); } catch (JexlException pe) { // expected JEXL.logger.error(pe); } } public void testMalformedScript2() throws Exception { // this will throw a TokenMgrErr, which we rethrow as a JexlException String badScript = "?"; try { JEXL.createScript(badScript); fail("Parsing \"" + badScript + "\" should result in a JexlException"); } catch (JexlException pe) { // expected JEXL.logger.error(pe); } } public void testMalformedScript3() throws Exception { // this will throw a TokenMgrErr, which we rethrow as a JexlException String badScript = "foo=1;bar=2;a?b:c:d;"; try { JEXL.createScript(badScript); fail("Parsing \"" + badScript + "\" should result in a JexlException"); } catch (JexlException pe) { // expected JEXL.logger.error(pe); } } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/parser/ParserTest.java100644 0 0 3363 11673634320 25505 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2.parser; import java.io.StringReader; import junit.framework.TestCase; /** * @since 1.0 * */ public class ParserTest extends TestCase { public ParserTest(String testName) { super(testName); } /** * parse test : see if we can parse a little script */ public void testParse1() throws Exception { Parser parser = new Parser(new StringReader(";")); SimpleNode sn = parser.parse(new StringReader("foo = 1;"), null); assertNotNull("parsed node is null", sn); } public void testParse2() throws Exception { Parser parser = new Parser(new StringReader(";")); SimpleNode sn = parser.parse(new StringReader("foo = \"bar\";"), null); assertNotNull("parsed node is null", sn); sn = parser.parse(new StringReader("foo = 'bar';"), null); assertNotNull("parsed node is null", sn); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/PublicFieldsTest.java100644 0 0 10324 11673634317 25343 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Tests public field set/get. */ @SuppressWarnings("boxing") public class PublicFieldsTest extends JexlTestCase { // some constants private static final String LOWER42 = "fourty-two"; private static final String UPPER42 = "FOURTY-TWO"; /** * An Inner class. */ public static class Inner { public double aDouble = 42.0; } /** * A Struct, all fields public */ public static class Struct { public Inner inner = new Inner(); public int anInt = 42; public String aString = LOWER42; } // a pub instance private Struct pub; // the JexlContext to use private JexlContext ctxt; public PublicFieldsTest() { super(createEngine(false)); } @Override public void setUp() { pub = new Struct(); ctxt = new MapContext(); ctxt.set("pub", pub); } public void testGetInt() throws Exception { Expression get = JEXL.createExpression("pub.anInt"); assertEquals(42, get.evaluate(ctxt)); JEXL.setProperty(pub, "anInt", -42); assertEquals(-42, get.evaluate(ctxt)); } public void testSetInt() throws Exception { Expression set = JEXL.createExpression("pub.anInt = value"); ctxt.set("value", -42); assertEquals(-42, set.evaluate(ctxt)); assertEquals(-42, JEXL.getProperty(pub, "anInt")); ctxt.set("value", 42); assertEquals(42, set.evaluate(ctxt)); assertEquals(42, JEXL.getProperty(pub, "anInt")); try { ctxt.set("value", UPPER42); assertEquals(null, set.evaluate(ctxt)); fail("should have thrown"); } catch(JexlException xjexl) {} } public void testGetString() throws Exception { Expression get = JEXL.createExpression("pub.aString"); assertEquals(LOWER42, get.evaluate(ctxt)); JEXL.setProperty(pub, "aString", UPPER42); assertEquals(UPPER42, get.evaluate(ctxt)); } public void testSetString() throws Exception { Expression set = JEXL.createExpression("pub.aString = value"); ctxt.set("value", UPPER42); assertEquals(UPPER42, set.evaluate(ctxt)); assertEquals(UPPER42, JEXL.getProperty(pub, "aString")); ctxt.set("value", LOWER42); assertEquals(LOWER42, set.evaluate(ctxt)); assertEquals(LOWER42, JEXL.getProperty(pub, "aString")); } public void testGetInnerDouble() throws Exception { Expression get = JEXL.createExpression("pub.inner.aDouble"); assertEquals(42.0, get.evaluate(ctxt)); JEXL.setProperty(pub, "inner.aDouble", -42); assertEquals(-42.0, get.evaluate(ctxt)); } public void testSetInnerDouble() throws Exception { Expression set = JEXL.createExpression("pub.inner.aDouble = value"); ctxt.set("value", -42.0); assertEquals(-42.0, set.evaluate(ctxt)); assertEquals(-42.0, JEXL.getProperty(pub, "inner.aDouble")); ctxt.set("value", 42.0); assertEquals(42.0, set.evaluate(ctxt)); assertEquals(42.0, JEXL.getProperty(pub, "inner.aDouble")); try { ctxt.set("value", UPPER42); assertEquals(null, set.evaluate(ctxt)); fail("should have thrown"); } catch(JexlException xjexl) {} } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/SandboxTest.java100644 0 0 22350 11673634321 24371 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.logging.Logger; import org.apache.commons.jexl2.introspection.Sandbox; import org.apache.commons.jexl2.introspection.SandboxUberspectImpl; import org.apache.commons.jexl2.introspection.Uberspect; /** * Tests sandbox features. */ public class SandboxTest extends JexlTestCase { static final Logger LOGGER = Logger.getLogger(VarTest.class.getName()); public static class Foo { String name; public String alias; public Foo(String name) { this.name = name; this.alias = name + "-alias"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String Quux() { return name + "-quux"; } } public void testCtorBlack() throws Exception { String expr = "new('" + Foo.class.getName() + "', '42')"; Script script = JEXL.createScript(expr); Object result; result = script.execute(null); assertEquals("42", ((Foo) result).getName()); Sandbox sandbox = new Sandbox(); sandbox.black(Foo.class.getName()).execute(""); Uberspect uber = new SandboxUberspectImpl(null, sandbox); JexlEngine sjexl = new JexlEngine(uber, null, null, null); sjexl.setStrict(true); script = sjexl.createScript(expr); try { result = script.execute(null); fail("ctor should not be accessible"); } catch (JexlException.Method xmethod) { // ok, ctor should not have been accessible LOGGER.info(xmethod.toString()); } } public void testMethodBlack() throws Exception { String expr = "foo.Quux()"; Script script = JEXL.createScript(expr, "foo"); Foo foo = new Foo("42"); Object result; result = script.execute(null, foo); assertEquals(foo.Quux(), result); Sandbox sandbox = new Sandbox(); sandbox.black(Foo.class.getName()).execute("Quux"); Uberspect uber = new SandboxUberspectImpl(null, sandbox); JexlEngine sjexl = new JexlEngine(uber, null, null, null); sjexl.setStrict(true); script = sjexl.createScript(expr, "foo"); try { result = script.execute(null, foo); fail("Quux should not be accessible"); } catch (JexlException.Method xmethod) { // ok, Quux should not have been accessible LOGGER.info(xmethod.toString()); } } public void testGetBlack() throws Exception { String expr = "foo.alias"; Script script = JEXL.createScript(expr, "foo"); Foo foo = new Foo("42"); Object result; result = script.execute(null, foo); assertEquals(foo.alias, result); Sandbox sandbox = new Sandbox(); sandbox.black(Foo.class.getName()).read("alias"); Uberspect uber = new SandboxUberspectImpl(null, sandbox); JexlEngine sjexl = new JexlEngine(uber, null, null, null); sjexl.setStrict(true); script = sjexl.createScript(expr, "foo"); try { result = script.execute(null, foo); fail("alias should not be accessible"); } catch (JexlException.Property xvar) { // ok, alias should not have been accessible LOGGER.info(xvar.toString()); } } public void testSetBlack() throws Exception { String expr = "foo.alias = $0"; Script script = JEXL.createScript(expr, "foo", "$0"); Foo foo = new Foo("42"); Object result; result = script.execute(null, foo, "43"); assertEquals("43", result); Sandbox sandbox = new Sandbox(); sandbox.black(Foo.class.getName()).write("alias"); Uberspect uber = new SandboxUberspectImpl(null, sandbox); JexlEngine sjexl = new JexlEngine(uber, null, null, null); sjexl.setStrict(true); script = sjexl.createScript(expr, "foo", "$0"); try { result = script.execute(null, foo, "43"); fail("alias should not be accessible"); } catch (JexlException.Property xvar) { // ok, alias should not have been accessible LOGGER.info(xvar.toString()); } } public void testCtorWhite() throws Exception { String expr = "new('" + Foo.class.getName() + "', '42')"; Script script; Object result; Sandbox sandbox = new Sandbox(); sandbox.white(Foo.class.getName()).execute(""); Uberspect uber = new SandboxUberspectImpl(null, sandbox); JexlEngine sjexl = new JexlEngine(uber, null, null, null); sjexl.setStrict(true); script = sjexl.createScript(expr); result = script.execute(null); assertEquals("42", ((Foo) result).getName()); } public void testMethodWhite() throws Exception { Foo foo = new Foo("42"); String expr = "foo.Quux()"; Script script; Object result; Sandbox sandbox = new Sandbox(); sandbox.white(Foo.class.getName()).execute("Quux"); Uberspect uber = new SandboxUberspectImpl(null, sandbox); JexlEngine sjexl = new JexlEngine(uber, null, null, null); sjexl.setStrict(true); script = sjexl.createScript(expr, "foo"); result = script.execute(null, foo); assertEquals(foo.Quux(), result); } public void testGetWhite() throws Exception { Foo foo = new Foo("42"); String expr = "foo.alias"; Script script; Object result; Sandbox sandbox = new Sandbox(); sandbox.white(Foo.class.getName()).read("alias"); sandbox.get(Foo.class.getName()).read().alias("alias", "ALIAS"); Uberspect uber = new SandboxUberspectImpl(null, sandbox); JexlEngine sjexl = new JexlEngine(uber, null, null, null); sjexl.setStrict(true); script = sjexl.createScript(expr, "foo"); result = script.execute(null, foo); assertEquals(foo.alias, result); script = sjexl.createScript("foo.ALIAS", "foo"); result = script.execute(null, foo); assertEquals(foo.alias, result); } public void testSetWhite() throws Exception { Foo foo = new Foo("42"); String expr = "foo.alias = $0"; Script script; Object result; Sandbox sandbox = new Sandbox(); sandbox.white(Foo.class.getName()).write("alias"); Uberspect uber = new SandboxUberspectImpl(null, sandbox); JexlEngine sjexl = new JexlEngine(uber, null, null, null); sjexl.setStrict(true); script = sjexl.createScript(expr, "foo", "$0"); result = script.execute(null, foo, "43"); assertEquals("43", result); assertEquals("43", foo.alias); } public void testRestrict() throws Exception { JexlContext context = new MapContext(); context.set("System", System.class); Sandbox sandbox = new Sandbox(); // only allow call to currentTimeMillis (avoid exit, gc, loadLibrary, etc) sandbox.white(System.class.getName()).execute("currentTimeMillis"); // can not create a new file sandbox.black(java.io.File.class.getName()).execute(""); Uberspect uber = new SandboxUberspectImpl(null, sandbox); JexlEngine sjexl = new JexlEngine(uber, null, null, null); sjexl.setStrict(true); String expr; Script script; Object result; script = sjexl.createScript("System.exit()"); try { result = script.execute(context); fail("should not allow calling exit!"); } catch (JexlException xjexl) { LOGGER.info(xjexl.toString()); } script = sjexl.createScript("new('java.io.File', '/tmp/should-not-be-created')"); try { result = script.execute(context); fail("should not allow creating a file"); } catch (JexlException xjexl) { LOGGER.info(xjexl.toString()); } expr = "System.currentTimeMillis()"; script = sjexl.createScript("System.currentTimeMillis()"); result = script.execute(context); assertNotNull(result); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/ScriptCallableTest.java100644 0 0 14457 11673634320 25667 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * Tests around asynchronous script execution and interrupts. */ public class ScriptCallableTest extends JexlTestCase { //Logger LOGGER = Logger.getLogger(VarTest.class.getName()); public void testFuture() throws Exception { Script e = JEXL.createScript("while(true);"); FutureTask future = new FutureTask(e.callable(null)); ExecutorService executor = Executors.newFixedThreadPool(1); executor.submit(future); try { future.get(100, TimeUnit.MILLISECONDS); fail("should have timed out"); } catch (TimeoutException xtimeout) { // ok, ignore } Thread.sleep(100); future.cancel(true); assertTrue(future.isCancelled()); } public void testCallable() throws Exception { Script e = JEXL.createScript("while(true);"); Callable c = e.callable(null); ExecutorService executor = Executors.newFixedThreadPool(1); Future future = executor.submit(c); try { future.get(100, TimeUnit.MILLISECONDS); fail("should have timed out"); } catch (TimeoutException xtimeout) { // ok, ignore } future.cancel(true); assertTrue(future.isCancelled()); } public static class TestContext extends MapContext implements NamespaceResolver { public Object resolveNamespace(String name) { return name == null ? this : null; } public int wait(int s) throws InterruptedException { Thread.sleep(1000 * s); return s; } public int waitInterrupt(int s) { try { Thread.sleep(1000 * s); return s; } catch(InterruptedException xint) { Thread.currentThread().interrupt(); } return -1; } public int runForever() { boolean x = false; while(true) { if (x) { break; } } return 1; } } public void testNoWait() throws Exception { Script e = JEXL.createScript("wait(0)"); Callable c = e.callable(new TestContext()); ExecutorService executor = Executors.newFixedThreadPool(1); Future future = executor.submit(c); Object t = future.get(2, TimeUnit.SECONDS); assertTrue(future.isDone()); assertEquals(0, t); } public void testWait() throws Exception { Script e = JEXL.createScript("wait(1)"); Callable c = e.callable(new TestContext()); ExecutorService executor = Executors.newFixedThreadPool(1); Future future = executor.submit(c); Object t = future.get(2, TimeUnit.SECONDS); assertEquals(1, t); } public void testCancelWait() throws Exception { Script e = JEXL.createScript("wait(10)"); Callable c = e.callable(new TestContext()); ExecutorService executor = Executors.newFixedThreadPool(1); Future future = executor.submit(c); try { future.get(100, TimeUnit.MILLISECONDS); fail("should have timed out"); } catch (TimeoutException xtimeout) { // ok, ignore } future.cancel(true); assertTrue(future.isCancelled()); } public void testCancelWaitInterrupt() throws Exception { Script e = JEXL.createScript("waitInterrupt(42)"); Callable c = e.callable(new TestContext()); ExecutorService executor = Executors.newFixedThreadPool(1); Future future = executor.submit(c); try { future.get(100, TimeUnit.MILLISECONDS); fail("should have timed out"); } catch (TimeoutException xtimeout) { // ok, ignore } future.cancel(true); assertTrue(future.isCancelled()); } public void testCancelForever() throws Exception { Script e = JEXL.createScript("runForever()"); Callable c = e.callable(new TestContext()); ExecutorService executor = Executors.newFixedThreadPool(1); Future future = executor.submit(c); try { future.get(100, TimeUnit.MILLISECONDS); fail("should have timed out"); } catch (TimeoutException xtimeout) { // ok, ignore } future.cancel(true); assertTrue(future.isCancelled()); } public void testCancelLoopWait() throws Exception { Script e = JEXL.createScript("while (true) { wait(10) }"); Callable c = e.callable(new TestContext()); ExecutorService executor = Executors.newFixedThreadPool(1); Future future = executor.submit(c); try { future.get(100, TimeUnit.MILLISECONDS); fail("should have timed out"); } catch (TimeoutException xtimeout) { // ok, ignore } future.cancel(true); assertTrue(future.isCancelled()); } } ././@LongLink100644 0 0 152 11673650056 10262 Lustar 0 0 commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineOptionalTest.javacommons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineOptionalTest100644 0 0 5031 11673634320 30754 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.commons.jexl2.scripting; import java.io.StringWriter; import javax.script.Compilable; import javax.script.CompiledScript; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import junit.framework.TestCase; public class JexlScriptEngineOptionalTest extends TestCase { private final JexlScriptEngineFactory factory = new JexlScriptEngineFactory(); private final ScriptEngineManager manager = new ScriptEngineManager(); private final ScriptEngine engine = manager.getEngineByName("jexl"); public void testOutput() throws Exception { String output = factory.getOutputStatement("foo\u00a9bar"); assertEquals("JEXL.out.print('foo\\u00a9bar')", output); // redirect output to capture evaluation result final StringWriter outContent = new StringWriter(); engine.getContext().setWriter(outContent); engine.eval(output); assertEquals("foo\u00a9bar", outContent.toString()); } public void testError() throws Exception { String error = "JEXL.err.print('ERROR')"; // redirect error to capture evaluation result final StringWriter outContent = new StringWriter(); engine.getContext().setErrorWriter(outContent); engine.eval(error); assertEquals("ERROR", outContent.toString()); } public void testCompilable() throws Exception { assertTrue("Engine should implement Compilable", engine instanceof Compilable); Compilable cengine = (Compilable) engine; CompiledScript script = cengine.compile("40 + 2"); assertEquals(Integer.valueOf(42), script.eval()); assertEquals(Integer.valueOf(42), script.eval()); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/scripting/JexlScriptEngineTest.java100644 0 0 15657 11673634320 30225 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.commons.jexl2.scripting; import java.io.Reader; import java.util.Arrays; import java.util.List; import java.util.Map; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import junit.framework.TestCase; public class JexlScriptEngineTest extends TestCase { private static final List NAMES = Arrays.asList("JEXL", "Jexl", "jexl", "JEXL2", "Jexl2", "jexl2"); private static final List EXTENSIONS = Arrays.asList("jexl", "jexl2"); private static final List MIMES = Arrays.asList("application/x-jexl", "application/x-jexl2"); public void testScriptEngineFactory() throws Exception { JexlScriptEngineFactory factory = new JexlScriptEngineFactory(); assertEquals("JEXL Engine", factory.getParameter(ScriptEngine.ENGINE)); assertEquals("2.0", factory.getParameter(ScriptEngine.ENGINE_VERSION)); assertEquals("JEXL", factory.getParameter(ScriptEngine.LANGUAGE)); assertEquals("2.0", factory.getParameter(ScriptEngine.LANGUAGE_VERSION)); assertNull(factory.getParameter("THREADING")); assertEquals(NAMES, factory.getParameter(ScriptEngine.NAME)); assertEquals(EXTENSIONS, factory.getExtensions()); assertEquals(MIMES, factory.getMimeTypes()); assertEquals("42;", factory.getProgram(new String[]{"42"})); assertEquals("str.substring(3,4)", factory.getMethodCallSyntax("str", "substring", new String[]{"3", "4"})); } public void testScriptingGetBy() throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); assertNotNull("Manager should not be null", manager); for (String name : NAMES) { ScriptEngine engine = manager.getEngineByName(name); assertNotNull("Engine should not be null (name)", engine); } for (String extension : EXTENSIONS) { ScriptEngine engine = manager.getEngineByExtension(extension); assertNotNull("Engine should not be null (extension)", engine); } for (String mime : MIMES) { ScriptEngine engine = manager.getEngineByMimeType(mime); assertNotNull("Engine should not be null (mime)", engine); } } public void testScripting() throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); assertNotNull("Manager should not be null", manager); ScriptEngine engine = manager.getEngineByName("jexl2"); final Integer initialValue = Integer.valueOf(123); assertEquals(initialValue,engine.eval("123")); assertEquals(initialValue,engine.eval("0;123"));// multiple statements long time1 = System.currentTimeMillis(); Long time2 = (Long) engine.eval( "sys=context.class.forName(\"java.lang.System\");" +"now=sys.currentTimeMillis();" ); assertTrue("Must take some time to process this",time1 <= time2.longValue()); engine.put("value", initialValue); assertEquals(initialValue,engine.get("value")); final Integer newValue = Integer.valueOf(124); assertEquals(newValue,engine.eval("old=value;value=value+1")); assertEquals(initialValue,engine.get("old")); assertEquals(newValue,engine.get("value")); assertEquals(engine.getContext(),engine.get(JexlScriptEngine.CONTEXT_KEY)); // Check behaviour of JEXL object assertEquals(engine.getContext().getReader(),engine.eval("JEXL.in")); assertEquals(engine.getContext().getWriter(),engine.eval("JEXL.out")); assertEquals(engine.getContext().getErrorWriter(),engine.eval("JEXL.err")); assertEquals(System.class,engine.eval("JEXL.System")); } public void testNulls() throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); assertNotNull("Manager should not be null", manager); ScriptEngine engine = manager.getEngineByName("jexl2"); assertNotNull("Engine should not be null (name)", engine); try { engine.eval((String)null); fail("Should have caused NPE"); } catch (NullPointerException e) { // NOOP } try { engine.eval((Reader)null); fail("Should have caused NPE"); } catch (NullPointerException e) { // NOOP } } public void testScopes() throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); assertNotNull("Manager should not be null", manager); ScriptEngine engine = manager.getEngineByName("JEXL"); assertNotNull("Engine should not be null (JEXL)", engine); manager.put("global",Integer.valueOf(1)); engine.put("local", Integer.valueOf(10)); manager.put("both",Integer.valueOf(7)); engine.put("both", Integer.valueOf(7)); engine.eval("local=local+1"); engine.eval("global=global+1"); engine.eval("both=both+1"); // should update engine value only engine.eval("newvar=42;"); assertEquals(Integer.valueOf(2),manager.get("global")); assertEquals(Integer.valueOf(11),engine.get("local")); assertEquals(Integer.valueOf(7),manager.get("both")); assertEquals(Integer.valueOf(8),engine.get("both")); assertEquals(Integer.valueOf(42),engine.get("newvar")); assertNull(manager.get("newvar")); } public void testDottedNames() throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); assertNotNull("Manager should not be null", manager); ScriptEngine engine = manager.getEngineByName("JEXL"); assertNotNull("Engine should not be null (JEXL)", engine); engine.eval("this.is.a.test=null"); assertNull(engine.get("this.is.a.test")); assertEquals(Boolean.TRUE, engine.eval("empty(this.is.a.test)")); final Object mymap = engine.eval("testmap={ 'key1' : 'value1', 'key2' : 'value2' }"); assertTrue(mymap instanceof Map); assertEquals(2,((Map)mymap).size()); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/ScriptTest.java100644 0 0 7051 11673634317 24225 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.io.File; import java.net.URL; /** * Tests for Script * @since 1.1 */ public class ScriptTest extends JexlTestCase { static final String TEST1 = "src/test/scripts/test1.jexl"; // test class for testScriptUpdatesContext // making this class private static will cause the test to fail. // this is due to unusual code in ClassMap.getAccessibleMethods(Class) // that treats non-public classes in a specific way. Why getAccessibleMethods // does this is not known yet. public static class Tester { private String code; public String getCode () { return code; } public void setCode(String c) { code = c; } } /** * Create a new test case. * @param name case name */ public ScriptTest(String name) { super(name); } /** * Test creating a script from a string. */ public void testSimpleScript() throws Exception { String code = "while (x < 10) x = x + 1;"; Script s = JEXL.createScript(code); JexlContext jc = new MapContext(); jc.set("x", new Integer(1)); Object o = s.execute(jc); assertEquals("Result is wrong", new Integer(10), o); assertEquals("getText is wrong", code, s.getText()); } public void testScriptFromFile() throws Exception { File testScript = new File(TEST1); Script s = JEXL.createScript(testScript); JexlContext jc = new MapContext(); jc.set("out", System.out); Object result = s.execute(jc); assertNotNull("No result", result); assertEquals("Wrong result", new Integer(7), result); } public void testScriptFromURL() throws Exception { URL testUrl = new File("src/test/scripts/test1.jexl").toURI().toURL(); Script s = JEXL.createScript(testUrl); JexlContext jc = new MapContext(); jc.set("out", System.out); Object result = s.execute(jc); assertNotNull("No result", result); assertEquals("Wrong result", new Integer(7), result); } public void testScriptUpdatesContext() throws Exception { String jexlCode = "resultat.setCode('OK')"; Expression e = JEXL.createExpression(jexlCode); Script s = JEXL.createScript(jexlCode); Tester resultatJexl = new Tester(); JexlContext jc = new MapContext(); jc.set("resultat", resultatJexl); resultatJexl.setCode(""); e.evaluate(jc); assertEquals("OK", resultatJexl.getCode()); resultatJexl.setCode(""); s.execute(jc); assertEquals("OK", resultatJexl.getCode()); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/UnifiedJEXLTest.java100644 0 0 35510 11673634317 25050 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Test cases for the UnifiedEL. */ public class UnifiedJEXLTest extends JexlTestCase { private static final JexlEngine ENGINE = createEngine(false); static { ENGINE.setSilent(false); ENGINE.setCache(128); } private static final UnifiedJEXL EL = new UnifiedJEXL(ENGINE); private static final Log LOG = LogFactory.getLog(UnifiedJEXL.class); private JexlContext context = null; private Map vars = null; @Override public void setUp() throws Exception { // ensure jul logging is only error java.util.logging.Logger.getLogger(JexlEngine.class.getName()).setLevel(java.util.logging.Level.SEVERE); vars = new HashMap(); context = new MapContext(vars); } @Override protected void tearDown() throws Exception { debuggerCheck(ENGINE); super.tearDown(); } /** Extract the source from a toString-ed expression. */ private String getSource(String tostring) { int len = tostring.length(); int sc = tostring.lastIndexOf(" /*= "); if (sc >= 0) { sc += " /*= ".length(); } int ec = tostring.lastIndexOf(" */"); if (sc >= 0 && ec >= 0 && ec > sc && ec < len) { return tostring.substring(sc, ec); } else { return tostring; } } public static class Froboz { int value; public Froboz(int v) { value = v; } public void setValue(int v) { value = v; } public int getValue() { return value; } public int plus10() { int i = value; value += 10; return i; } } public UnifiedJEXLTest(String testName) { super(testName); } public void testStatement() throws Exception { vars.put("froboz", new Froboz(123)); UnifiedJEXL.Expression check = EL.parse("${froboz.value = 32; froboz.plus10(); froboz.value}"); Object o = check.evaluate(context); assertEquals("Result is not 42", new Integer(42), o); Set> evars = check.getVariables(); assertEquals(2, evars.size()); } public void testAssign() throws Exception { UnifiedJEXL.Expression assign = EL.parse("${froboz.value = 10}"); UnifiedJEXL.Expression check = EL.parse("${froboz.value}"); Object o = assign.evaluate(context); assertEquals("Result is not 10", new Integer(10), o); o = check.evaluate(context); assertEquals("Result is not 10", new Integer(10), o); } public void testComposite() throws Exception { String source = "Dear ${p} ${name};"; UnifiedJEXL.Expression expr = EL.parse(source); vars.put("p", "Mr"); vars.put("name", "Doe"); assertTrue("expression should be immediate", expr.isImmediate()); Object o = expr.evaluate(context); assertEquals("Dear Mr Doe;", o); vars.put("p", "Ms"); vars.put("name", "Jones"); o = expr.evaluate(context); assertEquals("Dear Ms Jones;", o); assertEquals(source, getSource(expr.toString())); } public void testPrepareEvaluate() throws Exception { final String source = "Dear #{p} ${name};"; UnifiedJEXL.Expression expr = EL.parse("Dear #{p} ${name};"); assertTrue("expression should be deferred", expr.isDeferred()); Set> evars = expr.getVariables(); assertEquals(1, evars.size()); assertTrue(evars.contains(Arrays.asList("name"))); vars.put("name", "Doe"); UnifiedJEXL.Expression phase1 = expr.prepare(context); String as = phase1.asString(); assertEquals("Dear ${p} Doe;", as); Set> evars1 = phase1.getVariables(); assertEquals(1, evars1.size()); assertTrue(evars1.contains(Arrays.asList("p"))); vars.put("p", "Mr"); vars.put("name", "Should not be used in 2nd phase"); Object o = phase1.evaluate(context); assertEquals("Dear Mr Doe;", o); String p1 = getSource(phase1.toString()); assertEquals(source, getSource(phase1.toString())); assertEquals(source, getSource(expr.toString())); } public void testNested() throws Exception { final String source = "#{${hi}+'.world'}"; UnifiedJEXL.Expression expr = EL.parse(source); Set> evars = expr.getVariables(); assertEquals(1, evars.size()); assertTrue(evars.contains(Arrays.asList("hi"))); vars.put("hi", "greeting"); vars.put("greeting.world", "Hello World!"); assertTrue("expression should be deferred", expr.isDeferred()); Object o = expr.evaluate(context); assertEquals("Hello World!", o); assertEquals(source, getSource(expr.toString())); } public void testImmediate() throws Exception { JexlContext none = null; final String source = "${'Hello ' + 'World!'}"; UnifiedJEXL.Expression expr = EL.parse(source); UnifiedJEXL.Expression prepared = expr.prepare(none); assertEquals("prepare should return same expression", "Hello World!", prepared.asString()); Object o = expr.evaluate(none); assertTrue("expression should be immediate", expr.isImmediate()); assertEquals("Hello World!", o); assertEquals(source, getSource(expr.toString())); } public void testConstant() throws Exception { JexlContext none = null; final String source = "Hello World!"; UnifiedJEXL.Expression expr = EL.parse(source); assertTrue("prepare should return same expression", expr.prepare(none) == expr); Object o = expr.evaluate(none); assertTrue("expression should be immediate", expr.isImmediate()); assertEquals("Hello World!", o); assertEquals(source, getSource(expr.toString())); } public void testDeferred() throws Exception { JexlContext none = null; final String source = "#{'world'}"; UnifiedJEXL.Expression expr = EL.parse(source); assertTrue("expression should be deferred", expr.isDeferred()); String as = expr.prepare(none).asString(); assertEquals("prepare should return immediate version", "${'world'}", as); Object o = expr.evaluate(none); assertEquals("world", o); assertEquals(source, getSource(expr.toString())); } public void testEscape() throws Exception { JexlContext none = null; UnifiedJEXL.Expression expr; Object o; // $ and # are escapable in UnifiedJEXL expr = EL.parse("\\#{'world'}"); o = expr.evaluate(none); assertEquals("#{'world'}", o); expr = EL.parse("\\${'world'}"); o = expr.evaluate(none); assertEquals("${'world'}", o); } public void testEscapeString() throws Exception { UnifiedJEXL.Expression expr = EL.parse("\\\"${'world\\'s finest'}\\\""); JexlContext none = null; Object o = expr.evaluate(none); assertEquals("\"world's finest\"", o); } public void testNonEscapeString() throws Exception { UnifiedJEXL.Expression expr = EL.parse("c:\\some\\windows\\path"); JexlContext none = null; Object o = expr.evaluate(none); assertEquals("c:\\some\\windows\\path", o); } public void testMalformed() throws Exception { try { UnifiedJEXL.Expression expr = EL.parse("${'world'"); JexlContext none = null; expr.evaluate(none); fail("should be malformed"); } catch (UnifiedJEXL.Exception xjexl) { // expected String xmsg = xjexl.getMessage(); LOG.warn(xmsg); } } public void testMalformedNested() throws Exception { try { UnifiedJEXL.Expression expr = EL.parse("#{${hi} world}"); JexlContext none = null; expr.evaluate(none); fail("should be malformed"); } catch (UnifiedJEXL.Exception xjexl) { // expected String xmsg = xjexl.getMessage(); LOG.warn(xmsg); } } public void testBadContextNested() throws Exception { try { UnifiedJEXL.Expression expr = EL.parse("#{${hi}+'.world'}"); JexlContext none = null; expr.evaluate(none); fail("should be malformed"); } catch (UnifiedJEXL.Exception xjexl) { // expected String xmsg = xjexl.getMessage(); LOG.warn(xmsg); } } public void testCharAtBug() throws Exception { vars.put("foo", "abcdef"); UnifiedJEXL.Expression expr = EL.parse("${foo.substring(2,4)/*comment*/}"); Object o = expr.evaluate(context); assertEquals("cd", o); vars.put("bar", "foo"); try { ENGINE.setSilent(true); expr = EL.parse("#{${bar}+'.charAt(-2)'}"); expr = expr.prepare(context); o = expr.evaluate(context); assertEquals(null, o); } finally { ENGINE.setSilent(false); } } public void testTemplate0() throws Exception { String source = " $$ if(x) {\nx is ${x}\n $$ } else {\n${'no x'}\n$$ }\n"; StringWriter strw; String output; UnifiedJEXL.Template t = EL.createTemplate(source); vars.put("x", 42); strw = new StringWriter(); t.evaluate(context, strw); output = strw.toString(); assertEquals("x is 42\n", output); strw = new StringWriter(); vars.put("x", ""); t.evaluate(context, strw); output = strw.toString(); assertEquals("no x\n", output); String dstr = t.toString(); assertNotNull(dstr); } public void testTemplate1() throws Exception { String source = "$$ if(x) {\nx is ${x}\n$$ } else {\n${'no x'}\n$$ }\n"; StringWriter strw; String output; UnifiedJEXL.Template t = EL.createTemplate("$$", new StringReader(source), "x"); String dstr = t.asString(); assertNotNull(dstr); strw = new StringWriter(); t.evaluate(context, strw, 42); output = strw.toString(); assertEquals("x is 42\n", output); strw = new StringWriter(); t.evaluate(context, strw, ""); output = strw.toString(); assertEquals("no x\n", output); } public void testPrepareTemplate() throws Exception { String source = "$$ for(var x : list) {\n" + "${l10n}=#{x}\n" + "$$ }\n"; int[] args = { 42 }; UnifiedJEXL.Template tl10n = EL.createTemplate(source, "list"); String dstr = tl10n.asString(); assertNotNull(dstr); context.set("l10n", "valeur"); UnifiedJEXL.Template tpFR = tl10n.prepare(context); context.set("l10n", "value"); UnifiedJEXL.Template tpEN = tl10n.prepare(context); context.set("l10n", null); StringWriter strw; strw = new StringWriter(); tpFR.evaluate(context, strw, args); String outFR = strw.toString(); assertEquals("valeur=42\n", outFR); context.set("l10n", null); strw = new StringWriter(); tpEN.evaluate(context, strw, args); String outEN = strw.toString(); assertEquals("value=42\n", outEN); } public void test42() throws Exception { String test42 = "$$ for(var x : list) {\n" + "$$ if (x == 42) {\n" + "Life, the universe, and everything\n" + "$$ } else if (x > 42) {\n" + "The value ${x} is over fourty-two\n" + "$$ } else {\n" + "The value ${x} is under fourty-two\n" + "$$ }\n" + "$$ }\n"; UnifiedJEXL.Template t = EL.createTemplate("$$", new StringReader(test42), "list"); StringWriter strw = new StringWriter(); int[] list = {1, 3, 5, 42, 169}; t.evaluate(context, strw, list); String output = strw.toString(); String out42 = "The value 1 is under fourty-two\n" + "The value 3 is under fourty-two\n" + "The value 5 is under fourty-two\n" + "Life, the universe, and everything\n" + "The value 169 is over fourty-two\n"; assertEquals(out42, output); String dstr = t.asString(); assertNotNull(dstr); } public static class FrobozWriter extends PrintWriter { public FrobozWriter(Writer w) { super(w); } public void print(Froboz froboz) { super.print("froboz{"); super.print(froboz.value); super.print("}"); } @Override public String toString() { return out.toString(); } } public void testWriter() throws Exception { Froboz froboz = new Froboz(42); Writer writer = new FrobozWriter(new StringWriter()); UnifiedJEXL.Template t = EL.createTemplate("$$", new StringReader("$$$jexl.print(froboz)"), "froboz"); t.evaluate(context, writer, froboz); assertEquals("froboz{42}", writer.toString()); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/VarTest.java100644 0 0 22433 11673634320 23524 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Logger; /** * Tests local variables. */ public class VarTest extends JexlTestCase { static final Logger LOGGER = Logger.getLogger(VarTest.class.getName()); public VarTest(String testName) { super(testName); } public void testStrict() throws Exception { JexlContext map = new MapContext(); JexlContext ctxt = new ReadonlyContext(new MapContext()); JEXL.setStrict(true); Script e; e = JEXL.createScript("x"); try { Object o = e.execute(ctxt); fail("should have thrown an unknown var exception"); } catch(JexlException xjexl) { // ok since we are strict and x does not exist } e = JEXL.createScript("x = 42"); try { Object o = e.execute(ctxt); fail("should have thrown a readonly context exception"); } catch(JexlException xjexl) { // ok since we are strict and context is readonly } map.set("x", "fourty-two"); e = JEXL.createScript("x.theAnswerToEverything()"); try { Object o = e.execute(ctxt); fail("should have thrown an unknown method exception"); } catch(JexlException xjexl) { // ok since we are strict and method does not exist } } public void testLocalBasic() throws Exception { Script e = JEXL.createScript("var x; x = 42"); Object o = e.execute(null); assertEquals("Result is not 42", new Integer(42), o); } public void testLocalSimple() throws Exception { Script e = JEXL.createScript("var x = 21; x + x"); Object o = e.execute(null); assertEquals("Result is not 42", new Integer(42), o); } public void testLocalFor() throws Exception { Script e = JEXL.createScript("var y = 0; for(var x : [5, 17, 20]) { y = y + x; } y;"); Object o = e.execute(null); assertEquals("Result is not 42", new Integer(42), o); } public static class NumbersContext extends MapContext implements NamespaceResolver { public Object resolveNamespace(String name) { return name == null ? this : null; } public Object numbers() { return new int[]{5, 17, 20}; } } public void testLocalForFunc() throws Exception { JexlContext jc = new NumbersContext(); Script e = JEXL.createScript("var y = 0; for(var x : numbers()) { y = y + x; } y;"); Object o = e.execute(jc); assertEquals("Result is not 42", new Integer(42), o); } public void testLocalForFuncReturn() throws Exception { JexlContext jc = new NumbersContext(); Script e = JEXL.createScript("var y = 42; for(var x : numbers()) { if (x > 10) return x } y;"); Object o = e.execute(jc); assertEquals("Result is not 17", new Integer(17), o); assertTrue(toString(e.getVariables()), e.getVariables().isEmpty()); } /** * Generate a string representation of Set<List&t;String>>, useful to dump script variables * @param refs the variable reference set * @return the string representation */ String toString(Set> refs) { StringBuilder strb = new StringBuilder("{"); int r = 0; for (List strs : refs) { if (r++ > 0) { strb.append(", "); } strb.append("{"); for (int s = 0; s < strs.size(); ++s) { if (s > 0) { strb.append(", "); } strb.append('"'); strb.append(strs.get(s)); strb.append('"'); } strb.append("}"); } strb.append("}"); return strb.toString(); } /** * Creates a variable reference set from an array of array of strings. * @param refs the variable reference set * @return the set of variables */ Set> mkref(String[][] refs) { Set> set = new HashSet>(); for(String[] ref : refs) { set.add(Arrays.asList(ref)); } return set; } /** * Checks that two sets of variable references are equal * @param lhs the left set * @param rhs the right set * @return true if equal, false otherwise */ boolean eq(Set> lhs, Set> rhs) { if (lhs.size() != rhs.size()) { return false; } List llhs = stringify(lhs); List lrhs = stringify(rhs); for(int s = 0; s < llhs.size(); ++s) { String l = llhs.get(s); String r = lrhs.get(s); if (!l.equals(r)) { return false; } } return true; } List stringify(Set> sls) { List ls = new ArrayList(); for(List l : sls) { StringBuilder strb = new StringBuilder(); for(String s : l) { strb.append(s); strb.append('|'); } ls.add(strb.toString()); } Collections.sort(ls); return ls; } public void testRefs() throws Exception { Script e; Set> vars; Set> expect; e = JEXL.createScript("e[f]"); vars = e.getVariables(); expect = mkref(new String[][]{{"e"},{"f"}}); assertTrue(eq(expect, vars)); e = JEXL.createScript("e[f][g]"); vars = e.getVariables(); expect = mkref(new String[][]{{"e"},{"f"},{"g"}}); assertTrue(eq(expect, vars)); e = JEXL.createScript("e['f'].goo"); vars = e.getVariables(); expect = mkref(new String[][]{{"e","f","goo"}}); assertTrue(eq(expect, vars)); e = JEXL.createScript("e['f']"); vars = e.getVariables(); expect = mkref(new String[][]{{"e","f"}}); assertTrue(eq(expect, vars)); e = JEXL.createScript("e[f]['g']"); vars = e.getVariables(); expect = mkref(new String[][]{{"e"},{"f"}}); assertTrue(eq(expect, vars)); e = JEXL.createScript("e['f']['g']"); vars = e.getVariables(); expect = mkref(new String[][]{{"e","f","g"}}); assertTrue(eq(expect, vars)); e = JEXL.createScript("a['b'].c['d'].e"); vars = e.getVariables(); expect = mkref(new String[][]{{"a", "b", "c", "d", "e"}}); assertTrue(eq(expect, vars)); e = JEXL.createScript("a + b.c + b.c.d + e['f']"); //LOGGER.info(flattenedStr(e)); vars = e.getVariables(); expect = mkref(new String[][]{{"a"}, {"b", "c"}, {"b", "c", "d"}, {"e", "f"}}); assertTrue(eq(expect, vars)); } public void testMix() throws Exception { Script e; // x is a parameter, y a context variable, z a local variable e = JEXL.createScript("if (x) { y } else { var z = 2 * x}", "x"); Set> vars = e.getVariables(); String[] parms = e.getParameters(); String[] locals = e.getLocalVariables(); assertTrue(eq(mkref(new String[][]{{"y"}}), vars)); assertEquals(1, parms.length); assertEquals("x", parms[0]); assertEquals(1, locals.length); assertEquals("z", locals[0]); } public void testLiteral() throws Exception { Script e = JEXL.createScript("x.y[['z', 't']]"); Set> vars = e.getVariables(); assertEquals(1, vars.size()); assertTrue(eq(mkref(new String[][]{{"x", "y", "[ 'z', 't' ]"}}), vars)); e = JEXL.createScript("x.y[{'z': 't'}]"); vars = e.getVariables(); assertEquals(1, vars.size()); assertTrue(eq(mkref(new String[][]{{"x", "y", "{ 'z' : 't' }"}}), vars)); e = JEXL.createScript("x.y.'{ \\'z\\' : \\'t\\' }'"); vars = e.getVariables(); assertEquals(1, vars.size()); assertTrue(eq(mkref(new String[][]{{"x", "y", "{ 'z' : 't' }"}}), vars)); } } commons-jexl-2.1.1-src/src/test/java/org/apache/commons/jexl2/WhileTest.java100644 0 0 4165 11673634317 24034 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl2; /** * Tests for while statement. * @since 1.1 */ public class WhileTest extends JexlTestCase { public WhileTest(String testName) { super(testName); } public void testSimpleWhileFalse() throws Exception { Expression e = JEXL.createExpression("while (false) ;"); JexlContext jc = new MapContext(); Object o = e.evaluate(jc); assertNull("Result is not null", o); } public void testWhileExecutesExpressionWhenLooping() throws Exception { Expression e = JEXL.createExpression("while (x < 10) x = x + 1;"); JexlContext jc = new MapContext(); jc.set("x", new Integer(1)); Object o = e.evaluate(jc); assertEquals("Result is wrong", new Integer(10), o); } public void testWhileWithBlock() throws Exception { Expression e = JEXL.createExpression("while (x < 10) { x = x + 1; y = y * 2; }"); JexlContext jc = new MapContext(); jc.set("x", new Integer(1)); jc.set("y", new Integer(1)); Object o = e.evaluate(jc); assertEquals("Result is wrong", new Integer(512), o); assertEquals("x is wrong", new Integer(10), jc.get("x")); assertEquals("y is wrong", new Integer(512), jc.get("y")); } } commons-jexl-2.1.1-src/src/test/scripts/test1.jexl100644 0 0 2257 11673634321 17237 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // This tests for JEXL-47. AL header above tests for block comments. ## ## This is a test script ## if (out != null) out.println('Starting test script'); x = 1; y = 2; result = x * y + 5; if (out != null) out.println("The result is " + result); ## return the result. result; // JEXL-44 should ignore "quotes" here /* Trailing comments are also ignored */commons-jexl-2.1.1-src/jexl2-compat/ 40755 0 0 0 11673634317 14265 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/ 40755 0 0 0 11673634316 15053 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/main/ 40755 0 0 0 11673634317 16000 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/main/java/ 40755 0 0 0 11673634316 16720 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/ 40755 0 0 0 11673634316 17507 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/ 40755 0 0 0 11673634316 20730 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/ 40755 0 0 0 11673634316 22403 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/ 40755 0 0 0 11673634317 23346 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/context/ 40755 0 0 0 11673634316 25031 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/main/resources/ 40755 0 0 0 11673634317 20012 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/test/ 40755 0 0 0 11673634316 16032 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/test/java/ 40755 0 0 0 11673634316 16753 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/test/java/org/ 40755 0 0 0 11673634316 17542 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/test/java/org/apache/ 40755 0 0 0 11673634316 20763 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/test/java/org/apache/commons/ 40755 0 0 0 11673634316 22436 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/test/java/org/apache/commons/jexl/ 40755 0 0 0 11673634316 23400 5ustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/pom.xml100644 0 0 10176 11673634317 15724 0ustar 0 0 org.apache.commons commons-parent 22 4.0.0 org.apache.commons commons-jexl-compat Commons JEXL (1.x compatibility) 2.1-SNAPSHOT 2003 Jexl is an implementation of the JSTL Expression Language with extensions. http://commons.apache.org/jexl/ jira http://issues.apache.org/jira/browse/JEXL scm:svn:http://svn.apache.org/repos/asf/commons/proper/jexl/trunk scm:svn:https://svn.apache.org/repos/asf/commons/proper/jexl/trunk http://svn.apache.org/viewvc/commons/proper/jexl/trunk org.apache.maven.plugins maven-surefire-plugin **/*Test.java org.apache.maven.plugins maven-compiler-plugin 1.5 1.5 junit junit 3.8.1 test commons-logging commons-logging 1.1.1 org.apache.commons commons-jexl 2.1-SNAPSHOT 1.5 1.5 jexl-compat 2.1 RC1 JEXL 12310479 UTF-8 UTF-8 ././@LongLink100644 0 0 146 11673650056 10265 Lustar 0 0 commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/context/HashMapContext.javacommons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/context/HashMapContext.jav100644 0 0 3006 11673634316 30515 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl.context; import org.apache.commons.jexl.JexlContext; import java.util.HashMap; import java.util.Map; /** * Implementation of JexlContext based on a HashMap. * * @since 1.0 * * @version $Id$ */ public class HashMapContext extends HashMap implements JexlContext { /** serialization version id jdk13 generated. */ private static final long serialVersionUID = 5715964743204418854L; /** * {@inheritDoc} */ public void setVars(Map vars) { clear(); putAll(vars); } /** * {@inheritDoc} */ public Map getVars() { return this; } } commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/context/package.html100644 0 0 2513 11673634316 27410 0ustar 0 0 Package Documentation for org.apache.commons.jexl.context Package Simple JexlContext implementations.

Introduction

This package only contains one JexlContext implementation, the HashMapContext. A HashMapContext is simply an extension of HashMap which implements the JexlContext interface.

commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/Expression.java100644 0 0 2507 11673634316 26450 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; /** * Jexl-1.x compatible expression. * @since 2.0 * @version $Id$ */ public interface Expression extends org.apache.commons.jexl2.Expression { /** * Evaluates the expression with the variables contained in the * supplied {@link JexlContext}. * * @param context A JexlContext containing variables. * @return The result of this evaluation * @throws Exception on any error */ Object evaluate(JexlContext context) throws Exception; } commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/ExpressionFactory.java100644 0 0 3376 11673634317 30006 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; import org.apache.commons.jexl2.JexlEngine; /** * Creates Expression objects. *

* To create a JEXL Expression object, pass * valid JEXL syntax to the static createExpression() method: *

* *
 * String jexl = "array[1]";
 * Expression expression = ExpressionFactory.createExpression( jexl );
 * 
* *

* When an {@link Expression} object is created, the JEXL syntax is * parsed and verified. If the supplied expression is neither an * expression nor a reference, an exception is thrown from createException(). *

* *

* This is a convenience class; using an instance of a {@link JexlEngine} * that serves the same purpose with more control is recommended. *

* @since 1.0 * * @version $Id$ * @deprecated Create a JexlEngine and use the createScript method on that instead. */ @Deprecated public final class ExpressionFactory extends JexlOne {} commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/JexlContext.java100644 0 0 3370 11673634317 26560 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; import java.util.Map; /** * Holds a Map of variables which are referenced in a JEXL expression. * * @since 1.0 * * @version $Id$ */ public interface JexlContext { /** * Replaces variables in a JexlContext with the variables contained * in the supplied Map. When setVars() is called on a JexlContext, * it clears the current Map and puts each entry of the * supplied Map into the current variable Map. * * @param vars Contents of vars will be replaced with the content * of this Map */ void setVars(Map vars); /** * Retrives the Map of variables associated with this JexlContext. The * keys of this map correspond to variable names referenced in a * JEXL expression. * * @return A reference to the variable Map associated with this JexlContext. */ Map getVars(); } commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/JexlHelper.java100644 0 0 3650 11673634316 26353 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; import org.apache.commons.jexl.context.HashMapContext; /** * Helper to create a context. In the current implementation of JEXL, there * is one implementation of JexlContext - {@link HashMapContext}, and there * is no reason not to directly instantiate {@link HashMapContext} in your * own application. * * @since 1.0 * * @version $Id$ */ public class JexlHelper { /** singleton instance. */ protected static JexlHelper helper = new JexlHelper(); /** @return the single instance. */ protected static JexlHelper getInstance() { return helper; } /** * Returns a new {@link JexlContext}. * @return a new JexlContext */ public static JexlContext createContext() { return getInstance().newContext(); } /** * Creates and returns a new {@link JexlContext}. * The current implementation creates a new instance of * {@link HashMapContext}. * @return a new JexlContext */ protected JexlContext newContext() { return new HashMapContext(); } } commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/JexlOne.java100644 0 0 22441 11673634316 25674 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; import java.io.File; import java.net.URL; import org.apache.commons.jexl2.JexlEngine; import org.apache.commons.jexl2.Interpreter; import org.apache.commons.jexl2.JexlException; import org.apache.commons.jexl2.parser.JexlNode; import org.apache.commons.jexl2.parser.ASTJexlScript; /** * This implements Jexl-1.x (Jelly) compatible behaviors on top of Jexl-2.0. * @since 2.0 * @version $Id$ */ public class JexlOne { /** * Default cache size. */ private static final int CACHE_SIZE = 256; /** * Private constructor, ensure no instance. */ protected JexlOne() {} /** * Lazy JexlEngine singleton through on demand holder idiom. */ private static final class EngineHolder { /** The shared instance. */ static final JexlOneEngine JEXL10 = new JexlOneEngine(); /** * Non-instantiable. */ private EngineHolder() {} } /** * A Jexl1.x context wrapped into a Jexl2 context. */ private static final class ContextAdapter implements org.apache.commons.jexl2.JexlContext { /** The Jexl1.x context. */ private final JexlContext legacy; /** * Creates a jexl2.JexlContext from a jexl.JexlContext. * @param ctxt10 */ ContextAdapter(JexlContext ctxt10) { legacy = ctxt10; } /** * {@inheritDoc} */ public Object get(String name) { return legacy.getVars().get(name); } /** * {@inheritDoc} */ public void set(String name, Object value) { legacy.getVars().put(name, value); } /** * {@inheritDoc} */ public boolean has(String name) { return legacy.getVars().containsKey(name); } /** * Adapts a Jexl-1.x context to a Jexl-2.0 context. * @param aContext a oac.jexl context * @return an oac.jexl2 context */ static final org.apache.commons.jexl2.JexlContext adapt(JexlContext aContext) { return aContext == null ? JexlOneEngine.EMPTY_CONTEXT : new ContextAdapter(aContext); } } /** * An interpreter made compatible with v1.1 behavior (at least Jelly's expectations). */ private static final class JexlOneInterpreter extends Interpreter { /** * Creates an instance. * @param jexl the jexl engine * @param aContext the jexl context */ public JexlOneInterpreter(JexlEngine jexl, JexlContext aContext) { super(jexl, ContextAdapter.adapt(aContext), false, false); } /**{@inheritDoc}*/ @Override public Object interpret(JexlNode node) { try { return node.jjtAccept(this, null); } catch (JexlException xjexl) { Throwable e = xjexl.getCause(); if (e instanceof RuntimeException) { throw (RuntimeException) e; } if (e instanceof IllegalStateException) { throw (IllegalStateException) e; } throw new IllegalStateException(e.getMessage(), e); } } /**{@inheritDoc}*/ @Override protected Object invocationFailed(JexlException xjexl) { throw xjexl; } /**{@inheritDoc}*/ @Override protected Object unknownVariable(JexlException xjexl) { return null; } } /** * An engine that uses a JexlOneInterpreter. */ private static final class JexlOneEngine extends JexlEngine { /** * Default ctor, creates a cache and sets instance to verbose (ie non-silent). */ private JexlOneEngine() { super(); setCache(CACHE_SIZE); setSilent(false); } /**{@inheritDoc}*/ protected Interpreter createInterpreter(JexlContext context) { return new JexlOneInterpreter(this, context); } /** {@inheritDoc} */ @Override protected Script createScript(ASTJexlScript tree, String text) { return new JexlOneExpression(this, text, tree); } /** {@inheritDoc} */ @Override protected Expression createExpression(ASTJexlScript tree, String text) { return new JexlOneExpression(this, text, tree); } } /** * The specific Jexl-1.x expressions implementation. */ private static final class JexlOneExpression extends org.apache.commons.jexl2.ExpressionImpl implements Expression, Script { /** * Default local ctor. * * @param engine the interpreter to evaluate the expression * @param expr the expression. * @param ref the parsed expression. */ private JexlOneExpression(JexlOne.JexlOneEngine engine, String expr, ASTJexlScript ref) { super(engine, expr, ref); } /** * {@inheritDoc} */ public Object evaluate(JexlContext context) { return super.evaluate(ContextAdapter.adapt(context)); } /** * {@inheritDoc} */ public Object execute(JexlContext context) { return super.execute(ContextAdapter.adapt(context)); } } /** * Creates a Script from a String containing valid JEXL syntax. * This method parses the script which validates the syntax. * * @param scriptText A String containing valid JEXL syntax * @return A {@link Script} which can be executed with a * {@link JexlContext}. * @throws Exception An exception can be thrown if there is a * problem parsing the script. * @deprecated Create a JexlEngine and use the createScript method on that instead. */ @Deprecated public static Script createScript(String scriptText) throws Exception { return (Script) EngineHolder.JEXL10.createScript(scriptText); } /** * Creates a Script from a {@link File} containing valid JEXL syntax. * This method parses the script and validates the syntax. * * @param scriptFile A {@link File} containing valid JEXL syntax. * Must not be null. Must be a readable file. * @return A {@link Script} which can be executed with a * {@link JexlContext}. * @throws Exception An exception can be thrown if there is a problem * parsing the script. * @deprecated Create a JexlEngine and use the createScript method on that instead. */ @Deprecated public static Script createScript(File scriptFile) throws Exception { return (Script) EngineHolder.JEXL10.createScript(scriptFile); } /** * Creates a Script from a {@link URL} containing valid JEXL syntax. * This method parses the script and validates the syntax. * * @param scriptUrl A {@link URL} containing valid JEXL syntax. * Must not be null. Must be a readable file. * @return A {@link Script} which can be executed with a * {@link JexlContext}. * @throws Exception An exception can be thrown if there is a problem * parsing the script. * @deprecated Create a JexlEngine and use the createScript method on that instead. */ @Deprecated public static Script createScript(URL scriptUrl) throws Exception { return (Script) EngineHolder.JEXL10.createScript(scriptUrl); } /** * Creates an Expression from a String containing valid * JEXL syntax. This method parses the expression which * must contain either a reference or an expression. * @param expression A String containing valid JEXL syntax * @return An Expression object which can be evaluated with a JexlContext * @throws JexlException An exception can be thrown if there is a problem * parsing this expression, or if the expression is neither an * expression or a reference. * @deprecated Create a JexlEngine and use createExpression() on that */ @Deprecated public static Expression createExpression(String expression) { return (Expression) EngineHolder.JEXL10.createExpression(expression); } } commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/package.html100644 0 0 3577 11673634317 25740 0ustar 0 0 Package Documentation for org.apache.commons.jexl Package

Jexl-1.x compatible implementation.

This package only contains classes that re-implement Jexl-1.x interfaces and behaviors. This is intended to allow easier conversion to Jexl-2.0.

Jexl-2.0 changed a lot of APIs and behaviors, enough to warrant putting it in its own org.apache.commons.jexl2 package and avoid possible "jar-hell" cases. Those could have occured if someone was trying to use both Jexl-2.0 and Jexl-1.x.

This package contains the original Jexl-1.x main API namely ScriptFactory, ExpressionFactory, Script, Expression, JexlContext and JexlHelper. It is not 100% compatible with the original Jexl-1.x codeline but should be close enough for "casual" usage.

commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/Script.java100644 0 0 2605 11673634316 25554 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; /** * Jexl-1.x compatible script. * @since 2.0 * @version $Id$ */ public interface Script extends org.apache.commons.jexl2.Script { /** * Executes the script with the variables contained in the * supplied {@link JexlContext}. * * @param context A JexlContext containing variables. * @return The result of this script, usually the result of * the last statement. * @throws Exception on any script parse or execution error. */ Object execute(JexlContext context) throws Exception; } commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/ScriptFactory.java100644 0 0 3137 11673634317 27106 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; import org.apache.commons.jexl2.JexlEngine; /** *

* Creates {@link Script}s. To create a JEXL Script, pass * valid JEXL syntax to the static createScript() method: *

* *
 * String jexl = "y = x * 12 + 44; y = y * 4;";
 * Script script = ScriptFactory.createScript( jexl );
 * 
* *

* When an {@link Script} is created, the JEXL syntax is * parsed and verified. *

* *

* This is a convenience class; using an instance of a {@link JexlEngine} * that serves the same purpose with more control is recommended. *

* @since 1.1 * @version $Id$ * @deprecated Create a JexlEngine and use the createScript method on that instead. */ @Deprecated public final class ScriptFactory extends JexlOne {} commons-jexl-2.1.1-src/jexl2-compat/src/test/java/org/apache/commons/jexl/ScriptTest.java100644 0 0 7260 11673634316 26451 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; import junit.framework.TestCase; import java.io.File; import java.net.URL; /** * Tests for Script * @since 1.1 */ public class ScriptTest extends TestCase { static final String TEST1 = "../src/test/scripts/test1.jexl"; // test class for testScriptUpdatesContext // making this class private static will cause the test to fail. // this is due to unusual code in ClassMap.getAccessibleMethods(Class) // that treats non-public classes in a specific way. Why getAccessibleMethods // does this is not known yet. public static class Tester { private String code; public String getCode () { return code; } public void setCode(String c) { code = c; } } /** * Create a new test case. * @param name case name */ public ScriptTest(String name) { super(name); } /** * Test creating a script from a string. */ public void testSimpleScript() throws Exception { String code = "while (x < 10) x = x + 1;"; Script s = ScriptFactory.createScript(code); JexlContext jc = JexlHelper.createContext(); jc.getVars().put("x", new Integer(1)); Object o = s.execute(jc); assertEquals("Result is wrong", new Integer(10), o); assertEquals("getText is wrong", code, s.getText()); } public void testScriptFromFile() throws Exception { File testScript = new File(TEST1); Script s = ScriptFactory.createScript(testScript); JexlContext jc = JexlHelper.createContext(); jc.getVars().put("out", System.out); Object result = s.execute(jc); assertNotNull("No result", result); assertEquals("Wrong result", new Integer(7), result); } public void testScriptFromURL() throws Exception { URL testUrl = new File(TEST1).toURI().toURL(); Script s = ScriptFactory.createScript(testUrl); JexlContext jc = JexlHelper.createContext(); jc.getVars().put("out", System.out); Object result = s.execute(jc); assertNotNull("No result", result); assertEquals("Wrong result", new Integer(7), result); } public void testScriptUpdatesContext() throws Exception { String jexlCode = "resultat.setCode('OK')"; Expression e = ExpressionFactory.createExpression(jexlCode); Script s = ScriptFactory.createScript(jexlCode); Tester resultatJexl = new Tester(); JexlContext jc = JexlHelper.createContext(); jc.getVars().put("resultat", resultatJexl); resultatJexl.setCode(""); e.evaluate(jc); assertEquals("OK", resultatJexl.getCode()); resultatJexl.setCode(""); s.execute(jc); assertEquals("OK", resultatJexl.getCode()); } } commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/Script.java100644 0 0 2605 11673634316 25554 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; /** * Jexl-1.x compatible script. * @since 2.0 * @version $Id$ */ public interface Script extends org.apache.commons.jexl2.Script { /** * Executes the script with the variables contained in the * supplied {@link JexlContext}. * * @param context A JexlContext containing variables. * @return The result of this script, usually the result of * the last statement. * @throws Exception on any script parse or execution error. */ Object execute(JexlContext context) throws Exception; } commons-jexl-2.1.1-src/jexl2-compat/src/main/java/org/apache/commons/jexl/ScriptFactory.java100644 0 0 3137 11673634317 27106 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; import org.apache.commons.jexl2.JexlEngine; /** *

* Creates {@link Script}s. To create a JEXL Script, pass * valid JEXL syntax to the static createScript() method: *

* *
 * String jexl = "y = x * 12 + 44; y = y * 4;";
 * Script script = ScriptFactory.createScript( jexl );
 * 
* *

* When an {@link Script} is created, the JEXL syntax is * parsed and verified. *

* *

* This is a convenience class; using an instance of a {@link JexlEngine} * that serves the same purpose with more control is recommended. *

* @since 1.1 * @version $Id$ * @deprecated Create a JexlEngine and use the createScript method on that instead. */ @Deprecated public final class ScriptFactory extends JexlOne {} commons-jexl-2.1.1-src/jexl2-compat/src/test/java/org/apache/commons/jexl/ScriptTest.java100644 0 0 7260 11673634316 26451 0ustar 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jexl; import junit.framework.TestCase; import java.io.File; import java.net.URL; /** * Tests for Script * @since 1.1 */ public class ScriptTest extends TestCase { static final String TEST1 = "../src/test/scripts/test1.jexl"; // test class for testScriptUpdatesContext // making this class private static will cause the test to fail. // this is due to unusual code in ClassMap.getAccessibleMethods(Class) // that treats non-public classes in a specific way. Why getAccessibleMethods // does this is not known yet. public static class Tester { private String code; public String getCode () { return code;