View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.el;
18  
19  import java.lang.reflect.Array;
20  import java.lang.reflect.InvocationTargetException;
21  import java.util.List;
22  import java.util.Map;
23  
24  import javax.servlet.jsp.el.ELException;
25  import javax.servlet.jsp.el.FunctionMapper;
26  import javax.servlet.jsp.el.VariableResolver;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  /**
32   *
33   * <p>Represents an operator that obtains a Map entry, an indexed
34   * value, a property value, or an indexed property value of an object.
35   * The following are the rules for evaluating this operator:
36   *
37   * <ul><pre>
38   * Evaluating a[b] (assuming a.b == a["b"])
39   *   a is null
40   *     return null
41   *   b is null
42   *     return null
43   *   a is Map
44   *     !a.containsKey (b)
45   *       return null
46   *     a.get(b) == null
47   *       return null
48   *     otherwise
49   *       return a.get(b)
50   *   a is List or array
51   *     coerce b to int (using coercion rules)
52   *     coercion couldn't be performed
53   *       error
54   *     a.get(b) or Array.get(a, b) throws ArrayIndexOutOfBoundsException or IndexOutOfBoundsException
55   *       return null
56   *     a.get(b) or Array.get(a, b) throws other exception
57   *       error
58   *     return a.get(b) or Array.get(a, b)
59   * 
60   *   coerce b to String
61   *   b is a readable property of a
62   *     getter throws an exception
63   *       error
64   *     otherwise
65   *       return result of getter call
66   *
67   *   otherwise
68   *     error
69   * </pre></ul>
70   * 
71   * @author Nathan Abramson - Art Technology Group
72   * @author Shawn Bayern
73   * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: bayard $
74   **/
75  
76  public class ArraySuffix
77      extends ValueSuffix {
78      
79      //-------------------------------------
80      // Constants
81      //-------------------------------------
82      private static Log log = LogFactory.getLog(ArraySuffix.class);
83  
84      // Zero-argument array
85      static Object[] sNoArgs = new Object[0];
86  
87      //-------------------------------------
88      // Properties
89      //-------------------------------------
90      // property index
91  
92      Expression mIndex;
93  
94      public Expression getIndex() {
95          return mIndex;
96      }
97  
98      public void setIndex(Expression pIndex) {
99          mIndex = pIndex;
100     }
101 
102     //-------------------------------------
103     /**
104      *
105      * Constructor
106      **/
107     public ArraySuffix(Expression pIndex) {
108         mIndex = pIndex;
109     }
110 
111     //-------------------------------------
112     /**
113      *
114      * Gets the value of the index
115      **/
116     Object evaluateIndex(
117         VariableResolver pResolver,
118         FunctionMapper functions)
119         throws ELException {
120         return mIndex.evaluate(pResolver, functions);
121     }
122 
123     //-------------------------------------
124     /**
125      *
126      * Returns the operator symbol
127      **/
128     String getOperatorSymbol() {
129         return "[]";
130     }
131 
132     //-------------------------------------
133     // ValueSuffix methods
134     //-------------------------------------
135     /**
136      *
137      * Returns the expression in the expression language syntax
138      **/
139     public String getExpressionString() {
140         return "[" + mIndex.getExpressionString() + "]";
141     }
142 
143     //-------------------------------------
144     /**
145      *
146      * Evaluates the expression in the given context, operating on the
147      * given value.
148      **/
149     public Object evaluate(Object pValue, VariableResolver pResolver, FunctionMapper functions)
150     throws ELException {
151         Object indexVal;
152         String indexStr;
153         BeanInfoProperty property;
154         BeanInfoIndexedProperty ixproperty;
155 
156         // Check for null value
157         if (pValue == null) {
158             if (log.isWarnEnabled()) {
159                 log.warn(
160                     MessageUtil.getMessageWithArgs(
161                         Constants.CANT_GET_INDEXED_VALUE_OF_NULL, getOperatorSymbol()));
162                 return null;
163             }
164         }
165 
166         // Evaluate the index
167         else if ((indexVal = evaluateIndex(pResolver, functions))
168             == null) {
169             if (log.isWarnEnabled()) {
170                 log.warn(
171                     MessageUtil.getMessageWithArgs(
172                         Constants.CANT_GET_NULL_INDEX, getOperatorSymbol()));
173                 return null;
174             }
175         }
176 
177         // See if it's a Map
178         else if (pValue instanceof Map) {
179             Map val = (Map) pValue;
180             return val.get(indexVal);
181         }
182 
183         // See if it's a List or array
184         else if (pValue instanceof List ||
185             pValue.getClass().isArray()) {
186             Integer indexObj = Coercions.coerceToInteger(indexVal);
187             if (indexObj == null) {
188                 if (log.isErrorEnabled()) {
189                     String message = MessageUtil.getMessageWithArgs(
190                         Constants.BAD_INDEX_VALUE,
191                         getOperatorSymbol(), indexVal.getClass().getName());
192                     log.error(message);
193                     throw new ELException(message);
194                 }
195                 return null;
196             } else if (pValue instanceof List) {
197                 try {
198                     return ((List) pValue).get(indexObj.intValue());
199                 } catch (ArrayIndexOutOfBoundsException aob) {
200                     if (log.isWarnEnabled()) {
201                         log.warn(
202                             MessageUtil.getMessageWithArgs(
203                                 Constants.EXCEPTION_ACCESSING_LIST, indexObj), aob);
204                     }   
205                     return null;
206                 } catch (IndexOutOfBoundsException iob) {
207                     if (log.isWarnEnabled()) {
208                         log.warn(
209                             MessageUtil.getMessageWithArgs(
210                                 Constants.EXCEPTION_ACCESSING_LIST, indexObj), iob);                        
211                     }   
212                     return null;
213                 } catch (Throwable t) {
214                     if (log.isErrorEnabled()) {
215                         String message = MessageUtil.getMessageWithArgs(
216                             Constants.EXCEPTION_ACCESSING_LIST,
217                             indexObj);
218                         log.error(message, t);
219                         throw new ELException(message, t);
220                     }
221                     return null;
222                 }
223             } else {
224                 try {
225                     return Array.get(pValue, indexObj.intValue());
226                 } catch (ArrayIndexOutOfBoundsException aob) {
227                     if (log.isWarnEnabled()) {
228                         log.warn(
229                             MessageUtil.getMessageWithArgs(
230                                 Constants.EXCEPTION_ACCESSING_ARRAY, indexObj), aob);
231                     }
232                     return null;
233                 } catch (IndexOutOfBoundsException iob) {
234                     if (log.isWarnEnabled()) {
235                         log.warn(
236                             MessageUtil.getMessageWithArgs(
237                                 Constants.EXCEPTION_ACCESSING_ARRAY, indexObj), iob);
238                     }
239                     return null;
240                 } catch (Throwable t) {
241                     if (log.isErrorEnabled()) {
242                         String message = MessageUtil.getMessageWithArgs(
243                             Constants.EXCEPTION_ACCESSING_ARRAY,
244                             indexObj);
245                         log.error(message, t);
246                         throw new ELException(message, t);
247                     }
248                     return null;
249                 }
250             }
251         }
252 
253         // Coerce to a String for property access
254 
255         else if ((indexStr = Coercions.coerceToString(indexVal)) ==
256             null) {
257             return null;
258         }
259 
260         // Look for a JavaBean property
261         else if ((property = BeanInfoManager.getBeanInfoProperty
262             (pValue.getClass(), indexStr)) != null &&
263             property.getReadMethod() != null) {
264             try {
265                 return property.getReadMethod().invoke(pValue, sNoArgs);
266             } catch (InvocationTargetException exc) {
267                 if (log.isErrorEnabled()) {
268                     String message = MessageUtil.getMessageWithArgs(
269                         Constants.ERROR_GETTING_PROPERTY, indexStr, pValue.getClass().getName());
270                     Throwable t = exc.getTargetException();
271                     log.warn(message, t);
272                     throw new ELException(message, t);
273                 }
274                 return null;
275             } catch (Throwable t) {
276                 if (log.isErrorEnabled()) {
277                     String message = MessageUtil.getMessageWithArgs(
278                         Constants.ERROR_GETTING_PROPERTY, indexStr, pValue.getClass().getName());                    
279                     log.warn(message, t);
280                     throw new ELException(message, t);
281                 }
282                 return null;
283             }
284         } else {
285             if (log.isErrorEnabled()) {
286                 String message = MessageUtil.getMessageWithArgs(
287                     Constants.CANT_FIND_INDEX,
288                     indexVal,
289                     pValue.getClass().getName(),
290                     getOperatorSymbol());
291                 log.error(message);
292                 throw new ELException(message);                    
293             }
294             return null;          
295         }
296         return null;
297     }
298 
299     public ValueSuffix bindFunctions(final FunctionMapper functions) throws ELException {
300         return new ArraySuffix(mIndex.bindFunctions(functions));
301     }
302     //-------------------------------------
303 }