001: /*
002: * Copyright 2006, 2007 Odysseus Software GmbH
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package de.odysseus.el.tree.impl.ast;
017:
018: import java.lang.reflect.InvocationTargetException;
019: import java.lang.reflect.Method;
020:
021: import javax.el.ELContext;
022: import javax.el.ELException;
023: import javax.el.MethodInfo;
024: import javax.el.MethodNotFoundException;
025: import javax.el.PropertyNotFoundException;
026:
027: import de.odysseus.el.misc.LocalMessages;
028: import de.odysseus.el.misc.TypeConversions;
029: import de.odysseus.el.tree.Bindings;
030:
031: public abstract class AstProperty extends AstNode {
032: private final AstNode prefix;
033: private final boolean lvalue;
034: private final boolean strict; // allow null as property value?
035:
036: public AstProperty(AstNode prefix, boolean lvalue, boolean strict) {
037: this .prefix = prefix;
038: this .lvalue = lvalue;
039: this .strict = strict;
040: }
041:
042: protected abstract Object getProperty(Bindings bindings,
043: ELContext context) throws ELException;
044:
045: @Override
046: public final Object eval(Bindings bindings, ELContext context) {
047: Object base = prefix.eval(bindings, context);
048: if (base == null) {
049: return null;
050: }
051: Object property = getProperty(bindings, context);
052: if (property == null && strict) {
053: return null;
054: }
055: Object result = context.getELResolver().getValue(context, base,
056: property);
057: if (!context.isPropertyResolved()) {
058: throw new PropertyNotFoundException(LocalMessages.get(
059: "error.property.property.notfound", property, base));
060: }
061: return result;
062: }
063:
064: public final boolean isLiteralText() {
065: return false;
066: }
067:
068: public final boolean isLeftValue() {
069: return lvalue;
070: }
071:
072: public final Class<?> getType(Bindings bindings, ELContext context) {
073: if (!lvalue) {
074: return null;
075: }
076: Object base = prefix.eval(bindings, context);
077: if (base == null) {
078: throw new PropertyNotFoundException(LocalMessages.get(
079: "error.property.base.null", prefix));
080: }
081: Object property = getProperty(bindings, context);
082: if (property == null && strict) {
083: throw new PropertyNotFoundException(LocalMessages.get(
084: "error.property.property.notfound", "null", base));
085: }
086: Class result = context.getELResolver().getType(context, base,
087: property);
088: if (!context.isPropertyResolved()) {
089: throw new PropertyNotFoundException(LocalMessages.get(
090: "error.property.property.notfound", property, base));
091: }
092: return result;
093: }
094:
095: public final boolean isReadOnly(Bindings bindings, ELContext context)
096: throws ELException {
097: if (!lvalue) {
098: return true;
099: }
100: Object base = prefix.eval(bindings, context);
101: if (base == null) {
102: throw new PropertyNotFoundException(LocalMessages.get(
103: "error.property.base.null", prefix));
104: }
105: Object property = getProperty(bindings, context);
106: if (property == null && strict) {
107: throw new PropertyNotFoundException(LocalMessages.get(
108: "error.property.property.notfound", "null", base));
109: }
110: boolean result = context.getELResolver().isReadOnly(context,
111: base, property);
112: if (!context.isPropertyResolved()) {
113: throw new PropertyNotFoundException(LocalMessages.get(
114: "error.property.property.notfound", property, base));
115: }
116: return result;
117: }
118:
119: public final void setValue(Bindings bindings, ELContext context,
120: Object value) throws ELException {
121: if (!lvalue) {
122: throw new ELException(LocalMessages
123: .get("error.value.set.rvalue"));
124: }
125: Object base = prefix.eval(bindings, context);
126: if (base == null) {
127: throw new PropertyNotFoundException(LocalMessages.get(
128: "error.property.base.null", prefix));
129: }
130: Object property = getProperty(bindings, context);
131: if (property == null && strict) {
132: throw new PropertyNotFoundException(LocalMessages.get(
133: "error.property.property.notfound", "null", base));
134: }
135: context.getELResolver()
136: .setValue(context, base, property, value);
137: if (!context.isPropertyResolved()) {
138: throw new PropertyNotFoundException(LocalMessages.get(
139: "error.property.property.notfound", property, base));
140: }
141: }
142:
143: private Method findMethod(String name, Class<?> clazz,
144: Class<?> returnType, Class<?>[] paramTypes) {
145: Method method = null;
146: try {
147: method = clazz.getMethod(name, paramTypes);
148: } catch (NoSuchMethodException e) {
149: throw new MethodNotFoundException(LocalMessages.get(
150: "error.property.method.notfound", name, clazz));
151: }
152: if (returnType != null
153: && !returnType.isAssignableFrom(method.getReturnType())) {
154: throw new MethodNotFoundException(LocalMessages.get(
155: "error.property.method.notfound", name, clazz));
156: }
157: return method;
158: }
159:
160: public final MethodInfo getMethodInfo(Bindings bindings,
161: ELContext context, Class<?> returnType,
162: Class<?>[] paramTypes) {
163: Object base = prefix.eval(bindings, context);
164: if (base == null) {
165: throw new PropertyNotFoundException(LocalMessages.get(
166: "error.property.base.null", prefix));
167: }
168: Object property = getProperty(bindings, context);
169: if (property == null && strict) {
170: throw new PropertyNotFoundException(LocalMessages.get(
171: "error.property.method.notfound", "null", base));
172: }
173: String name = TypeConversions.coerceToString(property);
174: Method method = findMethod(name, base.getClass(), returnType,
175: paramTypes);
176: return new MethodInfo(method.getName(), method.getReturnType(),
177: paramTypes);
178: }
179:
180: public final Object invoke(Bindings bindings, ELContext context,
181: Class<?> returnType, Class<?>[] paramTypes,
182: Object[] paramValues) {
183: Object base = prefix.eval(bindings, context);
184: if (base == null) {
185: throw new PropertyNotFoundException(LocalMessages.get(
186: "error.property.base.null", prefix));
187: }
188: Object property = getProperty(bindings, context);
189: if (property == null && strict) {
190: throw new PropertyNotFoundException(LocalMessages.get(
191: "error.property.method.notfound", "null", base));
192: }
193: String name = TypeConversions.coerceToString(property);
194: Method method = findMethod(name, base.getClass(), returnType,
195: paramTypes);
196: try {
197: return method.invoke(base, paramValues);
198: } catch (IllegalAccessException e) {
199: throw new ELException(LocalMessages.get(
200: "error.property.method.access", name, base
201: .getClass()));
202: } catch (IllegalArgumentException e) {
203: throw new ELException(LocalMessages.get(
204: "error.property.method.invocation", name, base
205: .getClass()), e);
206: } catch (InvocationTargetException e) {
207: throw new ELException(LocalMessages.get(
208: "error.property.method.invocation", name, base
209: .getClass()), e.getCause());
210: }
211: }
212:
213: public AstNode getChild(int i) {
214: return i == 0 ? prefix : null;
215: }
216: }
|