1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.peaseplate.internal.lang.command;
21
22 import java.lang.reflect.Field;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.util.List;
26 import java.util.Locale;
27 import java.util.Map;
28
29 import org.peaseplate.TemplateRuntimeException;
30 import org.peaseplate.internal.BuildContext;
31 import org.peaseplate.internal.util.ReflectionException;
32 import org.peaseplate.internal.util.ReflectionUtils;
33 import org.peaseplate.locator.TemplateLocator;
34
35 public abstract class AbstractObjectCallCommand extends AbstractNativeCallCommand {
36
37 public AbstractObjectCallCommand(TemplateLocator locator, int line, int column, ICommand command, ICommand... parameterCommands) {
38 super(locator, line, column, command, parameterCommands);
39 }
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 protected abstract Object callObject(BuildContext context, Object onObject, Object identifier) throws TemplateRuntimeException;
63
64 protected Object callField(Object onObject, Field field) throws TemplateRuntimeException {
65 try {
66 return field.get(onObject);
67 }
68 catch (IllegalArgumentException e) {
69 throw new TemplateRuntimeException(
70 getLocator(), getLine(), getColumn(),
71 "Illegal argument exception when calling field \"" + field + "\"", e
72 );
73 }
74 catch (IllegalAccessException e) {
75 throw new TemplateRuntimeException(
76 getLocator(), getLine(), getColumn(),
77 "Cannot access field \"" + field + "\"", e
78 );
79 }
80 }
81
82 protected Object callMap(BuildContext context, Map<?, ?> onMap, Object identifier) throws TemplateRuntimeException {
83 if (hasParameters())
84 return callMethod(context, onMap, String.valueOf(identifier));
85
86 return onMap.get(identifier);
87 }
88
89 protected Object callList(List<?> onList, int index) throws TemplateRuntimeException {
90 if (hasParameters())
91 throw new TemplateRuntimeException(
92 getLocator(), getLine(), getColumn(), "Calls on a List must not have parameters"
93 );
94
95 if ((index < 0) || (index >= onList.size()))
96 return null;
97
98 return onList.get(index);
99 }
100
101 protected Object callArray(Object[] onArray, int index) throws TemplateRuntimeException {
102 if (hasParameters())
103 throw new TemplateRuntimeException(
104 getLocator(), getLine(), getColumn(), "Calls on an Array must not have parameters"
105 );
106
107 if ((index < 0) || (index >= onArray.length))
108 return null;
109
110 return onArray[index];
111 }
112
113 protected Object callFieldOrMethod(BuildContext context, Object onObject, String identifier) throws TemplateRuntimeException {
114 identifier = identifier.toLowerCase(Locale.getDefault());
115
116 if (!hasParameters()) {
117 Field field = getField(onObject.getClass(), identifier);
118
119 if (field != null)
120 return callField(onObject, field);
121 }
122
123 return callMethod(context, onObject, identifier);
124 }
125
126 protected Object callMethod(BuildContext context, Object onObject, String identifier) throws TemplateRuntimeException {
127 Method method = getMethod(onObject.getClass(), identifier.toLowerCase(Locale.getDefault()), getNumberOfParameters());
128
129 if (method == null)
130 throw new TemplateRuntimeException(
131 getLocator(), getLine(), getColumn(),
132 "No method matches " + ReflectionUtils.formatMethodName(onObject.getClass(), identifier, getNumberOfParameters())
133 );
134
135 return callMethod(context, onObject, method);
136 }
137
138 protected Object callMethod(BuildContext context, Object onObject, Method method) throws TemplateRuntimeException {
139 try {
140 Object[] parameters = ReflectionUtils.callParameterCommands(context, getParameterCommands(), method);
141
142 return method.invoke(onObject, parameters);
143 }
144 catch (ReflectionException e) {
145 throw new TemplateRuntimeException(
146 getLocator(), getLine(), getColumn(),
147 "Could not call " + method, e
148 );
149 }
150
151 catch (IllegalAccessException e) {
152 throw new TemplateRuntimeException(
153 getLocator(), getLine(), getColumn(),
154 "Illegal access on method " + method, e
155 );
156 }
157 catch (IllegalArgumentException e) {
158 throw new TemplateRuntimeException(
159 getLocator(), getLine(), getColumn(),
160 "Invalid argument when calling method " + method, e
161 );
162 }
163 catch (InvocationTargetException e) {
164 throw new TemplateRuntimeException(
165 getLocator(), getLine(), getColumn(),
166 "Call on " + method + " threw exception", e
167 );
168 }
169 }
170
171 protected abstract Field getField(Class<?> clazz, String identifier) throws TemplateRuntimeException;
172
173 protected Field findField(Class<?> clazz, String identifier) throws TemplateRuntimeException {
174 identifier = identifier.toLowerCase(Locale.getDefault());
175
176 return scanFields(clazz, identifier);
177 }
178
179 protected Field scanFields(Class<?> clazz, String identifier) throws TemplateRuntimeException {
180 Field[] fields = clazz.getFields();
181
182 for (int i=fields.length-1; i>=0; i-=1)
183 if (identifier.equalsIgnoreCase(fields[i].getName()))
184 return fields[i];
185
186 return null;
187 }
188
189 protected abstract Method getMethod(Class<?> clazz, String identifier, int numberOfParameters) throws TemplateRuntimeException;
190
191 }