001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.jexl; 018 019import java.io.File; 020import java.net.URL; 021import org.apache.commons.jexl2.JexlEngine; 022import org.apache.commons.jexl2.Interpreter; 023import org.apache.commons.jexl2.JexlException; 024import org.apache.commons.jexl2.parser.JexlNode; 025import org.apache.commons.jexl2.parser.ASTJexlScript; 026 027/** 028 * This implements Jexl-1.x (Jelly) compatible behaviors on top of Jexl-2.0. 029 * @since 2.0 030 * @version $Id$ 031 */ 032public class JexlOne { 033 /** 034 * Default cache size. 035 */ 036 private static final int CACHE_SIZE = 256; 037 038 /** 039 * Private constructor, ensure no instance. 040 */ 041 protected JexlOne() {} 042 043 044 /** 045 * Lazy JexlEngine singleton through on demand holder idiom. 046 */ 047 private static final class EngineHolder { 048 /** The shared instance. */ 049 static final JexlOneEngine JEXL10 = new JexlOneEngine(); 050 /** 051 * Non-instantiable. 052 */ 053 private EngineHolder() {} 054 } 055 056 057 /** 058 * A Jexl1.x context wrapped into a Jexl2 context. 059 */ 060 private static final class ContextAdapter implements org.apache.commons.jexl2.JexlContext { 061 /** The Jexl1.x context. */ 062 private final JexlContext legacy; 063 064 /** 065 * Creates a jexl2.JexlContext from a jexl.JexlContext. 066 * @param ctxt10 067 */ 068 ContextAdapter(JexlContext ctxt10) { 069 legacy = ctxt10; 070 } 071 072 /** 073 * {@inheritDoc} 074 */ 075 public Object get(String name) { 076 return legacy.getVars().get(name); 077 } 078 079 /** 080 * {@inheritDoc} 081 */ 082 public void set(String name, Object value) { 083 legacy.getVars().put(name, value); 084 } 085 086 /** 087 * {@inheritDoc} 088 */ 089 public boolean has(String name) { 090 return legacy.getVars().containsKey(name); 091 } 092 093 /** 094 * Adapts a Jexl-1.x context to a Jexl-2.0 context. 095 * @param aContext a oac.jexl context 096 * @return an oac.jexl2 context 097 */ 098 static final org.apache.commons.jexl2.JexlContext adapt(JexlContext aContext) { 099 return aContext == null ? JexlOneEngine.EMPTY_CONTEXT : new ContextAdapter(aContext); 100 } 101 } 102 103 104 /** 105 * An interpreter made compatible with v1.1 behavior (at least Jelly's expectations). 106 */ 107 private static final class JexlOneInterpreter extends Interpreter { 108 /** 109 * Creates an instance. 110 * @param jexl the jexl engine 111 * @param aContext the jexl context 112 */ 113 public JexlOneInterpreter(JexlEngine jexl, JexlContext aContext) { 114 super(jexl, ContextAdapter.adapt(aContext), false, false); 115 } 116 117 /**{@inheritDoc}*/ 118 @Override 119 public Object interpret(JexlNode node) { 120 try { 121 return node.jjtAccept(this, null); 122 } catch (JexlException xjexl) { 123 Throwable e = xjexl.getCause(); 124 if (e instanceof RuntimeException) { 125 throw (RuntimeException) e; 126 } 127 if (e instanceof IllegalStateException) { 128 throw (IllegalStateException) e; 129 } 130 throw new IllegalStateException(e.getMessage(), e); 131 } 132 } 133 134 /**{@inheritDoc}*/ 135 @Override 136 protected Object invocationFailed(JexlException xjexl) { 137 throw xjexl; 138 } 139 140 /**{@inheritDoc}*/ 141 @Override 142 protected Object unknownVariable(JexlException xjexl) { 143 return null; 144 } 145 } 146 147 148 /** 149 * An engine that uses a JexlOneInterpreter. 150 */ 151 private static final class JexlOneEngine extends JexlEngine { 152 /** 153 * Default ctor, creates a cache and sets instance to verbose (ie non-silent). 154 */ 155 private JexlOneEngine() { 156 super(); 157 setCache(CACHE_SIZE); 158 setSilent(false); 159 } 160 161 /**{@inheritDoc}*/ 162 protected Interpreter createInterpreter(JexlContext context) { 163 return new JexlOneInterpreter(this, context); 164 } 165 166 /** {@inheritDoc} */ 167 @Override 168 protected Script createScript(ASTJexlScript tree, String text) { 169 return new JexlOneExpression(this, text, tree); 170 } 171 172 /** {@inheritDoc} */ 173 @Override 174 protected Expression createExpression(ASTJexlScript tree, String text) { 175 return new JexlOneExpression(this, text, tree); 176 } 177 } 178 179 /** 180 * The specific Jexl-1.x expressions implementation. 181 */ 182 private static final class JexlOneExpression 183 extends org.apache.commons.jexl2.ExpressionImpl 184 implements Expression, Script { 185 /** 186 * Default local ctor. 187 * 188 * @param engine the interpreter to evaluate the expression 189 * @param expr the expression. 190 * @param ref the parsed expression. 191 */ 192 private JexlOneExpression(JexlOne.JexlOneEngine engine, String expr, ASTJexlScript ref) { 193 super(engine, expr, ref); 194 } 195 196 /** 197 * {@inheritDoc} 198 */ 199 public Object evaluate(JexlContext context) { 200 return super.evaluate(ContextAdapter.adapt(context)); 201 } 202 203 /** 204 * {@inheritDoc} 205 */ 206 public Object execute(JexlContext context) { 207 return super.execute(ContextAdapter.adapt(context)); 208 } 209 } 210 211 212 /** 213 * Creates a Script from a String containing valid JEXL syntax. 214 * This method parses the script which validates the syntax. 215 * 216 * @param scriptText A String containing valid JEXL syntax 217 * @return A {@link Script} which can be executed with a 218 * {@link JexlContext}. 219 * @throws Exception An exception can be thrown if there is a 220 * problem parsing the script. 221 * @deprecated Create a JexlEngine and use the createScript method on that instead. 222 */ 223 @Deprecated 224 public static Script createScript(String scriptText) throws Exception { 225 return (Script) EngineHolder.JEXL10.createScript(scriptText); 226 } 227 228 /** 229 * Creates a Script from a {@link File} containing valid JEXL syntax. 230 * This method parses the script and validates the syntax. 231 * 232 * @param scriptFile A {@link File} containing valid JEXL syntax. 233 * Must not be null. Must be a readable file. 234 * @return A {@link Script} which can be executed with a 235 * {@link JexlContext}. 236 * @throws Exception An exception can be thrown if there is a problem 237 * parsing the script. 238 * @deprecated Create a JexlEngine and use the createScript method on that instead. 239 */ 240 @Deprecated 241 public static Script createScript(File scriptFile) throws Exception { 242 return (Script) EngineHolder.JEXL10.createScript(scriptFile); 243 } 244 245 /** 246 * Creates a Script from a {@link URL} containing valid JEXL syntax. 247 * This method parses the script and validates the syntax. 248 * 249 * @param scriptUrl A {@link URL} containing valid JEXL syntax. 250 * Must not be null. Must be a readable file. 251 * @return A {@link Script} which can be executed with a 252 * {@link JexlContext}. 253 * @throws Exception An exception can be thrown if there is a problem 254 * parsing the script. 255 * @deprecated Create a JexlEngine and use the createScript method on that instead. 256 */ 257 @Deprecated 258 public static Script createScript(URL scriptUrl) throws Exception { 259 return (Script) EngineHolder.JEXL10.createScript(scriptUrl); 260 } 261 262 /** 263 * Creates an Expression from a String containing valid 264 * JEXL syntax. This method parses the expression which 265 * must contain either a reference or an expression. 266 * @param expression A String containing valid JEXL syntax 267 * @return An Expression object which can be evaluated with a JexlContext 268 * @throws JexlException An exception can be thrown if there is a problem 269 * parsing this expression, or if the expression is neither an 270 * expression or a reference. 271 * @deprecated Create a JexlEngine and use createExpression() on that 272 */ 273 @Deprecated 274 public static Expression createExpression(String expression) { 275 return (Expression) EngineHolder.JEXL10.createExpression(expression); 276 } 277}