1 package org.apache.velocity.runtime.parser.node;
2
3 import org.apache.velocity.context.InternalContextAdapter;
4 import org.apache.velocity.exception.MethodInvocationException;
5 import org.apache.velocity.exception.TemplateInitException;
6 import org.apache.velocity.exception.VelocityException;
7 import org.apache.velocity.runtime.RuntimeConstants;
8 import org.apache.velocity.runtime.log.Log;
9 import org.apache.velocity.runtime.parser.Parser;
10 import org.apache.velocity.util.ClassUtils;
11 import org.apache.velocity.util.introspection.VelMethod;
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 public class ASTIndex extends SimpleNode
38 {
39 private final String methodName = "get";
40
41
42
43
44 protected boolean strictRef = false;
45
46 public ASTIndex(int i)
47 {
48 super(i);
49 }
50
51 public ASTIndex(Parser p, int i)
52 {
53 super(p, i);
54 }
55
56 public Object init(InternalContextAdapter context, Object data)
57 throws TemplateInitException
58 {
59 super.init(context, data);
60 strictRef = rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false);
61 return data;
62 }
63
64
65
66 private final static Object[] noParams = {};
67 private final static Class[] noTypes = {};
68
69
70
71
72
73
74
75
76 public static Object adjMinusIndexArg(Object argument, Object o,
77 InternalContextAdapter context, SimpleNode node)
78 {
79 if (argument instanceof Integer && ((Integer)argument).intValue() < 0)
80 {
81
82
83 VelMethod method = ClassUtils.getMethod("size", noParams, noTypes,
84 o, context, node, false);
85 if (method == null)
86 {
87
88 throw new VelocityException(
89 "A 'size()' method required for negative value "
90 + ((Integer)argument).intValue() + " does not exist for class '"
91 + o.getClass().getName() + "' at " + Log.formatFileString(node));
92 }
93
94 Object size = null;
95 try
96 {
97 size = method.invoke(o, noParams);
98 }
99 catch (Exception e)
100 {
101 throw new VelocityException("Error trying to calls the 'size()' method on '"
102 + o.getClass().getName() + "' at " + Log.formatFileString(node), e);
103 }
104
105 int sizeint = 0;
106 try
107 {
108 sizeint = ((Integer)size).intValue();
109 }
110 catch (ClassCastException e)
111 {
112
113 throw new VelocityException("Method 'size()' on class '"
114 + o.getClass().getName() + "' returned '" + size.getClass().getName()
115 + "' when Integer was expected at " + Log.formatFileString(node));
116 }
117
118 argument = new Integer(sizeint + ((Integer)argument).intValue());
119 }
120
121
122 return argument;
123 }
124
125 public Object execute(Object o, InternalContextAdapter context)
126 throws MethodInvocationException
127 {
128 Object argument = jjtGetChild(0).value(context);
129
130 argument = adjMinusIndexArg(argument, o, context, this);
131 Object [] params = {argument};
132 Class[] paramClasses = {argument == null ? null : argument.getClass()};
133
134 VelMethod method = ClassUtils.getMethod(methodName, params, paramClasses,
135 o, context, this, strictRef);
136
137 if (method == null) return null;
138
139 try
140 {
141
142
143
144
145
146
147
148
149 Object obj = method.invoke(o, params);
150
151 if (obj == null)
152 {
153 if( method.getReturnType() == Void.TYPE)
154 {
155 return "";
156 }
157 }
158
159 return obj;
160 }
161
162
163
164 catch( RuntimeException e )
165 {
166 throw e;
167 }
168 catch( Exception e )
169 {
170 String msg = "Error invoking method 'get("
171 + (argument == null ? "null" : argument.getClass().getName())
172 + ")' in " + o.getClass().getName()
173 + " at " + Log.formatFileString(this);
174 log.error(msg, e);
175 throw new VelocityException(msg, e);
176 }
177 }
178 }