001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 1999 The Apache Software Foundation. All rights
005: * reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The end-user documentation included with the redistribution, if
020: * any, must include the following acknowlegement:
021: * "This product includes software developed by the
022: * Apache Software Foundation (http://www.apache.org/)."
023: * Alternately, this acknowlegement may appear in the software itself,
024: * if and wherever such third-party acknowlegements normally appear.
025: *
026: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
027: * Foundation" must not be used to endorse or promote products derived
028: * from this software without prior written permission. For written
029: * permission, please contact apache@apache.org.
030: *
031: * 5. Products derived from this software may not be called "Apache"
032: * nor may "Apache" appear in their names without prior written
033: * permission of the Apache Group.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of the Apache Software Foundation. For more
051: * information on the Apache Software Foundation, please see
052: * <http://www.apache.org/>.
053: *
054: */
055:
056: package org.apache.commons.el;
057:
058: import java.lang.reflect.Array;
059: import java.lang.reflect.InvocationTargetException;
060: import java.util.List;
061: import java.util.Map;
062: import javax.servlet.jsp.el.VariableResolver;
063: import javax.servlet.jsp.el.ELException;
064: import javax.servlet.jsp.el.FunctionMapper;
065:
066: /**
067: *
068: * <p>Represents an operator that obtains a Map entry, an indexed
069: * value, a property value, or an indexed property value of an object.
070: * The following are the rules for evaluating this operator:
071: *
072: * <ul><pre>
073: * Evaluating a[b] (assuming a.b == a["b"])
074: * a is null
075: * return null
076: * b is null
077: * return null
078: * a is Map
079: * !a.containsKey (b)
080: * return null
081: * a.get(b) == null
082: * return null
083: * otherwise
084: * return a.get(b)
085: * a is List or array
086: * coerce b to int (using coercion rules)
087: * coercion couldn't be performed
088: * error
089: * a.get(b) or Array.get(a, b) throws ArrayIndexOutOfBoundsException or IndexOutOfBoundsException
090: * return null
091: * a.get(b) or Array.get(a, b) throws other exception
092: * error
093: * return a.get(b) or Array.get(a, b)
094: *
095: * coerce b to String
096: * b is a readable property of a
097: * getter throws an exception
098: * error
099: * otherwise
100: * return result of getter call
101: *
102: * otherwise
103: * error
104: * </pre></ul>
105: *
106: * @author Nathan Abramson - Art Technology Group
107: * @author Shawn Bayern
108: * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: luehe $
109: **/
110:
111: public class ArraySuffix extends ValueSuffix {
112: //-------------------------------------
113: // Constants
114: //-------------------------------------
115:
116: // Zero-argument array
117: static Object[] sNoArgs = new Object[0];
118:
119: //-------------------------------------
120: // Properties
121: //-------------------------------------
122: // property index
123:
124: Expression mIndex;
125:
126: public Expression getIndex() {
127: return mIndex;
128: }
129:
130: public void setIndex(Expression pIndex) {
131: mIndex = pIndex;
132: }
133:
134: //-------------------------------------
135: /**
136: *
137: * Constructor
138: **/
139: public ArraySuffix(Expression pIndex) {
140: mIndex = pIndex;
141: }
142:
143: //-------------------------------------
144: /**
145: *
146: * Gets the value of the index
147: **/
148: Object evaluateIndex(VariableResolver pResolver,
149: FunctionMapper functions, Logger pLogger)
150: throws ELException {
151: return mIndex.evaluate(pResolver, functions, pLogger);
152: }
153:
154: //-------------------------------------
155: /**
156: *
157: * Returns the operator symbol
158: **/
159: String getOperatorSymbol() {
160: return "[]";
161: }
162:
163: //-------------------------------------
164: // ValueSuffix methods
165: //-------------------------------------
166: /**
167: *
168: * Returns the expression in the expression language syntax
169: **/
170: public String getExpressionString() {
171: return "[" + mIndex.getExpressionString() + "]";
172: }
173:
174: //-------------------------------------
175: /**
176: *
177: * Evaluates the expression in the given context, operating on the
178: * given value.
179: **/
180: public Object evaluate(Object pValue, VariableResolver pResolver,
181: FunctionMapper functions, Logger pLogger)
182: throws ELException {
183: Object indexVal;
184: String indexStr;
185: BeanInfoProperty property;
186: BeanInfoIndexedProperty ixproperty;
187:
188: // Check for null value
189: if (pValue == null) {
190: if (pLogger.isLoggingWarning()) {
191: pLogger.logWarning(
192: Constants.CANT_GET_INDEXED_VALUE_OF_NULL,
193: getOperatorSymbol());
194: }
195: return null;
196: }
197:
198: // Evaluate the index
199: else if ((indexVal = evaluateIndex(pResolver, functions,
200: pLogger)) == null) {
201: if (pLogger.isLoggingWarning()) {
202: pLogger.logWarning(Constants.CANT_GET_NULL_INDEX,
203: getOperatorSymbol());
204: }
205: return null;
206: }
207:
208: // See if it's a Map
209: else if (pValue instanceof Map) {
210: Map val = (Map) pValue;
211: return val.get(indexVal);
212: }
213:
214: // See if it's a List or array
215: else if (pValue instanceof List || pValue.getClass().isArray()) {
216: Integer indexObj = Coercions.coerceToInteger(indexVal,
217: pLogger);
218: if (indexObj == null) {
219: if (pLogger.isLoggingError()) {
220: pLogger.logError(Constants.BAD_INDEX_VALUE,
221: getOperatorSymbol(), indexVal.getClass()
222: .getName());
223: }
224: return null;
225: } else if (pValue instanceof List) {
226: try {
227: return ((List) pValue).get(indexObj.intValue());
228: } catch (ArrayIndexOutOfBoundsException exc) {
229: if (pLogger.isLoggingWarning()) {
230: pLogger.logWarning(
231: Constants.EXCEPTION_ACCESSING_LIST,
232: exc, indexObj);
233: }
234: return null;
235: } catch (IndexOutOfBoundsException exc) {
236: if (pLogger.isLoggingWarning()) {
237: pLogger.logWarning(
238: Constants.EXCEPTION_ACCESSING_LIST,
239: exc, indexObj);
240: }
241: return null;
242: } catch (Exception exc) {
243: if (pLogger.isLoggingError()) {
244: pLogger.logError(
245: Constants.EXCEPTION_ACCESSING_LIST,
246: exc, indexObj);
247: }
248: return null;
249: }
250: } else {
251: try {
252: return Array.get(pValue, indexObj.intValue());
253: } catch (ArrayIndexOutOfBoundsException exc) {
254: if (pLogger.isLoggingWarning()) {
255: pLogger.logWarning(
256: Constants.EXCEPTION_ACCESSING_ARRAY,
257: exc, indexObj);
258: }
259: return null;
260: } catch (IndexOutOfBoundsException exc) {
261: if (pLogger.isLoggingWarning()) {
262: pLogger.logWarning(
263: Constants.EXCEPTION_ACCESSING_ARRAY,
264: exc, indexObj);
265: }
266: return null;
267: } catch (Exception exc) {
268: if (pLogger.isLoggingError()) {
269: pLogger.logError(
270: Constants.EXCEPTION_ACCESSING_ARRAY,
271: exc, indexObj);
272: }
273: return null;
274: }
275: }
276: }
277:
278: // Coerce to a String for property access
279:
280: else if ((indexStr = Coercions
281: .coerceToString(indexVal, pLogger)) == null) {
282: return null;
283: }
284:
285: // Look for a JavaBean property
286: else if ((property = BeanInfoManager.getBeanInfoProperty(pValue
287: .getClass(), indexStr, pLogger)) != null
288: && property.getReadMethod() != null) {
289: try {
290: return property.getReadMethod().invoke(pValue, sNoArgs);
291: } catch (InvocationTargetException exc) {
292: if (pLogger.isLoggingError()) {
293: pLogger.logError(Constants.ERROR_GETTING_PROPERTY,
294: exc.getTargetException(), indexStr, pValue
295: .getClass().getName());
296: }
297: return null;
298: } catch (Exception exc) {
299: if (pLogger.isLoggingError()) {
300: pLogger.logError(Constants.ERROR_GETTING_PROPERTY,
301: exc, indexStr, pValue.getClass().getName());
302: }
303: return null;
304: }
305: }
306:
307: else {
308: if (pLogger.isLoggingError()) {
309: pLogger.logError(Constants.CANT_FIND_INDEX, indexVal,
310: pValue.getClass().getName(),
311: getOperatorSymbol());
312: }
313: return null;
314: }
315: }
316:
317: //-------------------------------------
318: }
|