View Javadoc

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             // expected
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             // expected
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             // expected
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             // expected
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             // expected
232         }
233     }
234 
235     private static class NoExplicitToString {
236         // this class does not directly declare toString()
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 }