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.el; 018 019import java.lang.reflect.Array; 020import java.lang.reflect.InvocationTargetException; 021import java.util.List; 022import java.util.Map; 023 024import javax.servlet.jsp.el.ELException; 025import javax.servlet.jsp.el.FunctionMapper; 026import javax.servlet.jsp.el.VariableResolver; 027 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030 031/** 032 * 033 * <p>Represents an operator that obtains a Map entry, an indexed 034 * value, a property value, or an indexed property value of an object. 035 * The following are the rules for evaluating this operator: 036 * 037 * <ul><pre> 038 * Evaluating a[b] (assuming a.b == a["b"]) 039 * a is null 040 * return null 041 * b is null 042 * return null 043 * a is Map 044 * !a.containsKey (b) 045 * return null 046 * a.get(b) == null 047 * return null 048 * otherwise 049 * return a.get(b) 050 * a is List or array 051 * coerce b to int (using coercion rules) 052 * coercion couldn't be performed 053 * error 054 * a.get(b) or Array.get(a, b) throws ArrayIndexOutOfBoundsException or IndexOutOfBoundsException 055 * return null 056 * a.get(b) or Array.get(a, b) throws other exception 057 * error 058 * return a.get(b) or Array.get(a, b) 059 * 060 * coerce b to String 061 * b is a readable property of a 062 * getter throws an exception 063 * error 064 * otherwise 065 * return result of getter call 066 * 067 * otherwise 068 * error 069 * </pre></ul> 070 * 071 * @author Nathan Abramson - Art Technology Group 072 * @author Shawn Bayern 073 * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: bayard $ 074 **/ 075 076public class ArraySuffix 077 extends ValueSuffix { 078 079 //------------------------------------- 080 // Constants 081 //------------------------------------- 082 private static Log log = LogFactory.getLog(ArraySuffix.class); 083 084 // Zero-argument array 085 static Object[] sNoArgs = new Object[0]; 086 087 //------------------------------------- 088 // Properties 089 //------------------------------------- 090 // property index 091 092 Expression mIndex; 093 094 public Expression getIndex() { 095 return mIndex; 096 } 097 098 public void setIndex(Expression pIndex) { 099 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}