View Javadoc

1   /***
2    * Licensed under the Artistic License; you may not use this file
3    * except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    *      http://displaytag.sourceforge.net/license.html
7    *
8    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
9    * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10   * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11   */
12  package org.displaytag.decorator;
13  
14  import java.lang.reflect.InvocationTargetException;
15  import java.util.HashMap;
16  import java.util.Map;
17  
18  import javax.servlet.jsp.PageContext;
19  
20  import org.apache.commons.beanutils.PropertyUtils;
21  import org.apache.commons.lang.BooleanUtils;
22  
23  
24  /***
25   * <p>
26   * This class provides some basic functionality for all objects which serve as decorators for the objects in the List
27   * being displayed.
28   * <p>
29   * <p>
30   * Decorator should never be subclassed directly. Use TableDecorator instead
31   * </p>
32   * @author mraible
33   * @author Fabrizio Giustina
34   * @version $Revision: 1.15 $ ($Author: fgiust $)
35   */
36  abstract class Decorator
37  {
38  
39      /***
40       * Char used to separate class name and property in the cache key.
41       */
42      private static final char CLASS_PROPERTY_SEPARATOR = '#';
43  
44      /***
45       * property info cache contains classname#propertyname Strings as keys and Booleans as values.
46       */
47      private static Map propertyMap = new HashMap();
48  
49      /***
50       * page context.
51       */
52      private PageContext pageContext;
53  
54      /***
55       * decorated object. Usually a List
56       */
57      private Object decoratedObject;
58  
59      /***
60       * Initialize the TableTecorator instance.
61       * @param context PageContext
62       * @param decorated decorated object (usually a list)
63       */
64      public void init(PageContext context, Object decorated)
65      {
66          this.pageContext = context;
67          this.decoratedObject = decorated;
68      }
69  
70      /***
71       * returns the page context.
72       * @return PageContext
73       */
74      public PageContext getPageContext()
75      {
76          return this.pageContext;
77      }
78  
79      /***
80       * returns the decorated object.
81       * @return Object
82       */
83      public Object getDecoratedObject()
84      {
85          return this.decoratedObject;
86      }
87  
88      /***
89       * Called at the end of evaluation to clean up instance variable. A subclass of Decorator can override this method
90       * but should always call super.finish() before return
91       */
92      public void finish()
93      {
94          this.pageContext = null;
95          this.decoratedObject = null;
96      }
97  
98      /***
99       * Check if a getter exists for a given property. Uses cached info if property has already been requested. This
100      * method only check for a simple property, if pPropertyName contains multiple tokens only the first part is
101      * evaluated
102      * @param propertyName name of the property to check
103      * @return boolean true if the decorator has a getter for the given property
104      */
105     public boolean hasGetterFor(String propertyName)
106     {
107         String simpleProperty = propertyName;
108 
109         // get the simple (not nested) bean property
110         int indexOfDot = simpleProperty.indexOf('.');
111         if (indexOfDot > 0)
112         {
113             simpleProperty = simpleProperty.substring(0, indexOfDot);
114         }
115 
116         Boolean cachedResult = (Boolean) propertyMap.get(getClass().getName()
117             + CLASS_PROPERTY_SEPARATOR
118             + simpleProperty);
119 
120         if (cachedResult != null)
121         {
122             return cachedResult.booleanValue();
123         }
124 
125         // not already cached... check
126         boolean hasGetter = searchGetterFor(propertyName);
127 
128         // save in cache
129         propertyMap.put(getClass().getName() + CLASS_PROPERTY_SEPARATOR + simpleProperty, BooleanUtils
130             .toBooleanObject(hasGetter));
131 
132         // and return
133         return hasGetter;
134 
135     }
136 
137     /***
138      * Looks for a getter for the given property using introspection.
139      * @param propertyName name of the property to check
140      * @return boolean true if the decorator has a getter for the given property
141      */
142     public boolean searchGetterFor(String propertyName)
143     {
144 
145         Class type = null;
146 
147         try
148         {
149             // using getPropertyType instead of isReadable since isReadable doesn't support mapped properties.
150             // Note that this method usually returns null if a property is not found and doesn't throw any exception
151             // also for non existent properties
152             type = PropertyUtils.getPropertyType(this, propertyName);
153         }
154         catch (IllegalAccessException e)
155         {
156             // ignore
157         }
158         catch (InvocationTargetException e)
159         {
160             // ignore
161         }
162         catch (NoSuchMethodException e)
163         {
164             // ignore
165         }
166 
167         return type != null;
168 
169     }
170 
171 }