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  import org.displaytag.model.TableModel;
23  
24  
25  /**
26   * <p>
27   * This class provides some basic functionality for all objects which serve as decorators for the objects in the List
28   * being displayed.
29   * <p>
30   * <p>
31   * Decorator should never be subclassed directly. Use TableDecorator instead
32   * </p>
33   * @author mraible
34   * @author Fabrizio Giustina
35   * @version $Revision: 1084 $ ($Author: fgiust $)
36   */
37  abstract class Decorator
38  {
39  
40      /**
41       * Char used to separate class name and property in the cache key.
42       */
43      private static final char CLASS_PROPERTY_SEPARATOR = '#';
44  
45      /**
46       * property info cache contains classname#propertyname Strings as keys and Booleans as values.
47       */
48      private static Map propertyMap = new HashMap();
49  
50      /**
51       * page context.
52       */
53      private PageContext pageContext;
54  
55      /**
56       * decorated object. Usually a List
57       */
58      private Object decoratedObject;
59  
60      /**
61       * The table model.
62       * @since 1.1
63       */
64      protected TableModel tableModel;
65  
66      /**
67       * Initialize the TableTecorator instance.
68       * @param pageContext PageContext
69       * @param decorated decorated object (usually a list)
70       * @deprecated use #init(PageContext, Object, TableModel)
71       * @see #init(PageContext, Object, TableModel)
72       */
73      public void init(PageContext pageContext, Object decorated)
74      {
75          this.pageContext = pageContext;
76          this.decoratedObject = decorated;
77      }
78  
79      /**
80       * Initialize the TableTecorator instance.
81       * @param pageContext PageContext
82       * @param decorated decorated object (usually a list)
83       * @param tableModel table model
84       */
85      public void init(PageContext pageContext, Object decorated, TableModel tableModel)
86      {
87          // temporary used for backward (source) compatibility
88          init(pageContext, decorated);
89          this.tableModel = tableModel;
90      }
91  
92      /**
93       * returns the page context.
94       * @return PageContext
95       */
96      public PageContext getPageContext()
97      {
98          return this.pageContext;
99      }
100 
101     /**
102      * returns the decorated object.
103      * @return Object
104      */
105     public Object getDecoratedObject()
106     {
107         return this.decoratedObject;
108     }
109 
110     /**
111      * Called at the end of evaluation to clean up instance variable. A subclass of Decorator can override this method
112      * but should always call super.finish() before return
113      */
114     public void finish()
115     {
116         this.pageContext = null;
117         this.decoratedObject = null;
118     }
119 
120     /**
121      * Check if a getter exists for a given property. Uses cached info if property has already been requested. This
122      * method only check for a simple property, if pPropertyName contains multiple tokens only the first part is
123      * evaluated
124      * @param propertyName name of the property to check
125      * @return boolean true if the decorator has a getter for the given property
126      */
127     public boolean hasGetterFor(String propertyName)
128     {
129         String simpleProperty = propertyName;
130 
131         // get the simple (not nested) bean property
132         int indexOfDot = simpleProperty.indexOf('.');
133         if (indexOfDot > 0)
134         {
135             simpleProperty = simpleProperty.substring(0, indexOfDot);
136         }
137 
138         Boolean cachedResult = (Boolean) propertyMap.get(getClass().getName()
139             + CLASS_PROPERTY_SEPARATOR
140             + simpleProperty);
141 
142         if (cachedResult != null)
143         {
144             return cachedResult.booleanValue();
145         }
146 
147         // not already cached... check
148         boolean hasGetter = searchGetterFor(propertyName);
149 
150         // save in cache
151         propertyMap.put(getClass().getName() + CLASS_PROPERTY_SEPARATOR + simpleProperty, BooleanUtils
152             .toBooleanObject(hasGetter));
153 
154         // and return
155         return hasGetter;
156 
157     }
158 
159     /**
160      * Looks for a getter for the given property using introspection.
161      * @param propertyName name of the property to check
162      * @return boolean true if the decorator has a getter for the given property
163      */
164     public boolean searchGetterFor(String propertyName)
165     {
166 
167         Class type = null;
168 
169         try
170         {
171             // using getPropertyType instead of isReadable since isReadable doesn't support mapped properties.
172             // Note that this method usually returns null if a property is not found and doesn't throw any exception
173             // also for non existent properties
174             type = PropertyUtils.getPropertyType(this, propertyName);
175         }
176         catch (IllegalAccessException e)
177         {
178             // ignore
179         }
180         catch (InvocationTargetException e)
181         {
182             // ignore
183         }
184         catch (NoSuchMethodException e)
185         {
186             // ignore
187         }
188 
189         return type != null;
190 
191     }
192 
193 }