View Javadoc

1   /*
2   Copyright (C) 2004 Grid Systems, S.A.
3   
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License, version 2, as
6   published by the Free Software Foundation.
7   
8   This program is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12  
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  */
17  package com.gridsystems.beanfilter;
18  
19  import java.beans.BeanInfo;
20  import java.beans.Introspector;
21  import java.beans.PropertyDescriptor;
22  import java.lang.reflect.Method;
23  import java.util.HashMap;
24  import java.util.Locale;
25  import java.util.Map;
26  
27  /**
28   * Bean Fields Description for evaluation.
29   *
30   * @author Rodrigo Ruiz
31   * @author Xmas
32   * @version 1.0
33   */
34  public final class BeanDescriptor {
35    /**
36     * Descriptor cache.
37     */
38    private static final Map<Class<?>, BeanDescriptor> DESCRIPTORS
39      = new HashMap<Class<?>, BeanDescriptor>();
40  
41    /**
42     * Factory method. It gets a descriptor instance for the specified class.
43     *
44     * @param c  The class for which we want a descriptor instance
45     * @return   The descriptor
46     */
47    public static synchronized BeanDescriptor getInstance(Class<?> c) {
48      BeanDescriptor d = (BeanDescriptor)DESCRIPTORS.get(c);
49      if (d == null) {
50        d = new BeanDescriptor(c);
51        DESCRIPTORS.put(c, d);
52      }
53      return new BeanDescriptor(c, d.accessors);
54    }
55  
56    /**
57     * Property reader methods map.
58     */
59    private Map<String, Method> accessors = new HashMap<String, Method>();
60  
61    /**
62     * Push in stack last field processed.
63     * @param parent Parent Class
64     * @param token Token
65     * @throws EvalException If Error
66     */
67    public void push(Class<?> parent, Token token) throws EvalException {
68      // Check if field is correct
69      String field = token.image;
70  
71      BeanDescriptor bd = BeanDescriptor.getInstance(parent);
72      Method method = bd.getMethod(field);
73      if (method == null) {
74        // FTR005=Unknown field ''{2}'' at position [{0}, {1}])
75        throw new EvalException("FTR005", token.beginLine, token.beginColumn, field);
76      }
77    }
78  
79    /**
80     * Creates a new instance.
81     *
82     * @param c  The class to describe
83     * @param accessors List of accessors for this class
84     */
85    private BeanDescriptor(Class<?> c, Map<String, Method> accessors) {
86      this(c);
87      this.accessors = accessors;
88    }
89  
90    /**
91     * Creates a new instance.
92     *
93     * @param c  The class to describe
94     */
95    private BeanDescriptor(Class<?> c) {
96      inspect(c);
97    }
98  
99    /**
100    * Discovers the possible field paths and caches them.
101    *
102    * @param c      The class to inspect
103    *
104    */
105   private void inspect(Class<?> c) {
106     try {
107       BeanInfo info = Introspector.getBeanInfo(c);
108 
109       PropertyDescriptor[] props = info.getPropertyDescriptors();
110       int count = props == null ? 0 : props.length;
111       for (int i = 0; i < count; i++) {
112         if ("class".equals(props[i].getName())) {
113           continue;
114         }
115         Method m = props[i].getReadMethod();
116 
117         String name = props[i].getName().toUpperCase(Locale.UK);
118         accessors.put(name, m);
119       }
120     } catch (Exception e) { }
121   }
122 
123   /**
124    * Gets the method needed to read the specified field.
125    *
126    * @param field  The field path
127    * @return The method to access to value of <code>field</code>.
128    *         Null if number of methods obtained is zero or greater than 1.
129    */
130   public synchronized Method getMethod(String field) {
131     field = field.toUpperCase(Locale.UK);
132     Method m = (Method)accessors.get(field);
133     return m;
134   }
135 
136 }