1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package net.sf.ehcache.search.attribute;
18
19 import java.lang.reflect.Method;
20 import java.util.List;
21 import java.util.Vector;
22
23 import junit.framework.TestCase;
24 import net.sf.ehcache.Element;
25 import net.sf.ehcache.config.InvalidConfigurationException;
26
27 public class ReflectionAttributeExtractorTest extends TestCase {
28
29 /***
30 * Makes sure that any caching done in the extractor is thread safe in the face of heterogenous input types
31 */
32 public void testHeterogenousTypesThreaded() throws InterruptedException {
33 final List<Throwable> errors = new Vector<Throwable>();
34
35 final int NUM = 500000;
36
37 final ReflectionAttributeExtractor method = new ReflectionAttributeExtractor("value.getValue()");
38 final ReflectionAttributeExtractor field = new ReflectionAttributeExtractor("value.value");
39
40 class Task implements Runnable {
41
42 private final int type;
43 private int count;
44
45 Task(int type) {
46 this.type = type;
47 }
48
49 public void run() {
50 try {
51 for (int i = 0; i < NUM; i++) {
52 assertEquals(count, method.attributeFor(element(), ""));
53 assertEquals(count, field.attributeFor(element(), ""));
54 }
55 } catch (Throwable t) {
56 t.printStackTrace();
57 errors.add(t);
58 }
59 }
60
61 private Element element() {
62 switch (type) {
63 case 0: {
64 return new Element("k", new Person1(count++));
65 }
66 case 1: {
67 return new Element("k", new Person2(count++));
68 }
69 case 2: {
70 return new Element("k", new Person3(count++));
71 }
72 case 3: {
73 return new Element("k", new Person4(count++));
74 }
75 case 4: {
76 return new Element("k", new Person5(count++));
77 }
78 default: {
79 throw new AssertionError(type);
80 }
81 }
82 }
83 }
84
85 Thread threads[] = new Thread[5];
86 for (int i = 0; i < threads.length; i++) {
87 threads[i] = new Thread(new Task(i));
88 }
89
90 for (Thread t : threads) {
91 t.start();
92 }
93
94 for (Thread t : threads) {
95 t.join();
96 }
97
98 assertEquals(0, errors.size());
99 }
100
101 public void testBasic() {
102 Element element = new Element("k", "v");
103
104 ReflectionAttributeExtractor rae;
105
106 rae = new ReflectionAttributeExtractor("element");
107 assertEquals(element, rae.attributeFor(element, ""));
108
109 rae = new ReflectionAttributeExtractor("ELEMENT");
110 assertEquals(element, rae.attributeFor(element, ""));
111
112 rae = new ReflectionAttributeExtractor("element.getObjectKey()");
113 assertEquals("k", rae.attributeFor(element, ""));
114
115 rae = new ReflectionAttributeExtractor("key");
116 assertEquals("k", rae.attributeFor(element, ""));
117
118 rae = new ReflectionAttributeExtractor("KEY");
119 assertEquals("k", rae.attributeFor(element, ""));
120
121 rae = new ReflectionAttributeExtractor("value");
122 assertEquals("v", rae.attributeFor(element, ""));
123
124 rae = new ReflectionAttributeExtractor("VALUE");
125 assertEquals("v", rae.attributeFor(element, ""));
126
127 rae = new ReflectionAttributeExtractor("key.toString()");
128 assertEquals("k", rae.attributeFor(element, ""));
129
130 rae = new ReflectionAttributeExtractor("value.toString()");
131 assertEquals("v", rae.attributeFor(element, ""));
132
133 element = new Element("k", new Ref(new Ref("v")));
134 rae = new ReflectionAttributeExtractor("value.reference.reference.toString()");
135 assertEquals("v", rae.attributeFor(element, ""));
136 }
137
138 public void testInheritedMethodCall() {
139 Object value = new NoExplicitToString();
140 Element element = new Element("k", value);
141
142 ReflectionAttributeExtractor rae = new ReflectionAttributeExtractor("value.toString()");
143 assertEquals(value.toString(), rae.attributeFor(element, ""));
144 }
145
146 public void testNullInChain() {
147
148 try {
149 Element e = new Element("k", new Ref(null));
150 ReflectionAttributeExtractor rae = new ReflectionAttributeExtractor("value.reference.toString()");
151 rae.attributeFor(e, "");
152 fail();
153 } catch (AttributeExtractorException aee) {
154
155 }
156
157 try {
158 Element e = new Element("k", new Ref(null));
159 ReflectionAttributeExtractor rae = new ReflectionAttributeExtractor("value.reference.reference");
160 rae.attributeFor(e, "");
161 fail();
162 } catch (AttributeExtractorException aee) {
163
164 }
165 }
166
167 public void testMethodThrowsException() {
168 RuntimeException re = new RuntimeException();
169 try {
170 Ref ref = new Ref(re);
171 ref.re = re;
172 Element e = new Element("k", ref);
173
174 ReflectionAttributeExtractor rae = new ReflectionAttributeExtractor("value.exception()");
175 rae.attributeFor(e, "");
176 fail();
177 } catch (AttributeExtractorException aee) {
178 assertEquals(re, aee.getCause());
179 }
180 }
181
182 public void testInheritedField() {
183 Element element = new Element("k", new Sub());
184
185 ReflectionAttributeExtractor rae = new ReflectionAttributeExtractor("value.field");
186 assertEquals("base", rae.attributeFor(element, ""));
187 }
188
189 public void testExceptions() {
190 Element element = new Element("k", "v");
191
192 try {
193 ReflectionAttributeExtractor rae = new ReflectionAttributeExtractor("value.FIELD_DOES_NOT_EXIST");
194 rae.attributeFor(element, "");
195 fail();
196 } catch (AttributeExtractorException aee) {
197
198 }
199
200 try {
201 ReflectionAttributeExtractor rae = new ReflectionAttributeExtractor("value.METHOD_DOES_NOT_EXIST()");
202 rae.attributeFor(element, "");
203 fail();
204 } catch (AttributeExtractorException aee) {
205
206 }
207 }
208
209 public void testWhitespaceIgnored() {
210 Element element = new Element("k", "v");
211
212 ReflectionAttributeExtractor rae = new ReflectionAttributeExtractor(" value.toString() ");
213 assertEquals("v", rae.attributeFor(element, ""));
214 }
215
216 public void testInvalidExpressions() {
217 tryInvalidExpression("");
218 tryInvalidExpression(" ");
219 tryInvalidExpression("tim");
220 tryInvalidExpression("element1.toString()");
221 tryInvalidExpression("element..toString()");
222 tryInvalidExpression("element.1ref");
223 tryInvalidExpression("element . toString()");
224 }
225
226 private void tryInvalidExpression(String expr) {
227 try {
228 new ReflectionAttributeExtractor(expr);
229 fail(expr);
230 } catch (InvalidConfigurationException ice) {
231
232 }
233 }
234
235 private static class NoExplicitToString {
236
237
238 static {
239 for (Method m : NoExplicitToString.class.getDeclaredMethods()) {
240 if (m.getName().equals("toString()")) {
241 throw new AssertionError(m);
242 }
243 }
244 }
245
246 }
247
248 private static class Base {
249 private final Object field = "base";
250 }
251
252 private static class Sub extends Base {
253
254 }
255
256 private static class Ref {
257 public RuntimeException re;
258
259 public Ref(Object ref) {
260 this.reference = ref;
261 }
262
263 public void exception() {
264 if (re != null) {
265 throw re;
266 }
267 }
268
269 public Object reference;
270 }
271
272 private static class Person1 {
273 private final int value;
274
275 Person1(int value) {
276 this.value = value;
277 }
278
279 public int getValue() {
280 return value;
281 }
282 }
283
284 private static class Person2 {
285 private final int value;
286
287 Person2(int value) {
288 this.value = value;
289 }
290
291 public int getValue() {
292 return value;
293 }
294 }
295
296 private static class Person3 {
297 private final int value;
298
299 Person3(int value) {
300 this.value = value;
301 }
302
303 public int getValue() {
304 return value;
305 }
306 }
307
308 private static class Person4 {
309 private final int value;
310
311 Person4(int value) {
312 this.value = value;
313 }
314
315 public int getValue() {
316 return value;
317 }
318 }
319
320 private static class Person5 {
321 private final int value;
322
323 Person5(int value) {
324 this.value = value;
325 }
326
327 public int getValue() {
328 return value;
329 }
330 }
331
332 }