View Javadoc

1   package net.sf.stitch.crud;
2   
3   import java.lang.reflect.Field;
4   import java.lang.reflect.Method;
5   import java.lang.reflect.Modifier;
6   import java.util.Collection;
7   import java.util.Collections;
8   import java.util.LinkedHashMap;
9   import java.util.Map;
10  
11  import javax.persistence.Entity;
12  
13  /**
14   * <a href="http://en.wikipedia.org/wiki/Create%2C_read%2C_update_and_delete">CRUD</a>
15   * Profile for an Entity class.
16   * @author Logan Hutchinson
17   */
18  public class CrudEntity
19  {
20      /** package.EntityClass */
21      private final String entityClassName;
22      /** EntityClass */
23      private final String entityShortName;
24      /** entityClass */
25      private final String entityPrefix;
26  
27      /** Seam Component Name of the EntityHome class related to the Entity. */
28      private final String entityHome;
29      /** Seam Component Name of the EntityQuery class related to the Entity. */
30      private final String entityQuery;
31  
32      /** Collection of Fields/Getters for entity class */
33      private final Map<String,CrudEntityProperty> entityFields;
34  
35      /**
36       * Construct a new CrudProfile for a given entity class.
37       * @param entityClassName
38       */
39      public CrudEntity (final String entityClassName) throws ClassNotFoundException
40      {
41          // Validate parameter...
42          final Class<?> entityClass = Class.forName(entityClassName);
43          if (!entityClass.isAnnotationPresent(Entity.class))
44          {
45              throw new IllegalArgumentException("CrudEntity may only be instantiated for a class annotated with @Entity");
46          }
47  
48          //  Initialize object...
49          this.entityClassName = entityClassName;
50          this.entityShortName = entityClassName.substring(entityClassName.lastIndexOf('.') + 1);
51          this.entityPrefix = Character.toLowerCase(entityShortName.charAt(0)) + entityShortName.substring(1);
52          this.entityFields = buildEntityFields(entityClass);
53  
54          //  TODO:  Consider providing an annotation to override the defaults...
55          this.entityHome = this.entityPrefix + "Home";
56          this.entityQuery = this.entityPrefix + "List";
57      }
58  
59      protected static boolean isGetter (final Method m)
60      {
61          return isBeanMethod(m, "get");
62      }
63  
64      protected static boolean isSetter (final Method m)
65      {
66          return isBeanMethod(m, "set");
67      }
68  
69      protected static boolean isBeanMethod (final Method m, final String prefix)
70      {
71          final String methodName = m.getName();
72          return methodName.startsWith(prefix)
73              && methodName.length() > prefix.length()
74              && Character.isUpperCase(methodName.charAt(prefix.length()));
75      }
76      
77      protected static String fieldNameFromXetter (final String methodName)
78      {
79          return Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
80      }
81      
82      private Map<String,CrudEntityProperty> buildEntityFields (final Class<?> entityClass)
83      {
84          final Map<String,CrudEntityProperty> fieldMap = new LinkedHashMap<String,CrudEntityProperty>();
85          
86          //  Iterate through all of the non-transient fields...
87          for (final Field f : entityClass.getDeclaredFields())
88          {
89              final int fieldModifiers = f.getModifiers();
90              if (!Modifier.isTransient(fieldModifiers))
91              {
92                  final String name = f.getName();
93                  fieldMap.put(name, new CrudEntityProperty(f));
94              }
95          }
96          //  Iterate through all of the methods looking for getters and setters...
97          for (final Method m : entityClass.getDeclaredMethods())
98          {
99              final int methodModifiers = m.getModifiers();
100             if (!Modifier.isStatic(methodModifiers))
101             {
102                 if (isGetter(m))
103                 {
104                     final String fieldName = fieldNameFromXetter(m.getName());
105                     final CrudEntityProperty prop = fieldMap.get(fieldName);
106                     if (null != prop)
107                     {
108                         prop.setGetter(m);
109                     }
110                 }
111                 else if (isSetter(m))
112                 {
113                     final String fieldName = fieldNameFromXetter(m.getName());
114                     final CrudEntityProperty prop = fieldMap.get(fieldName);
115                     if (null != prop)
116                     {
117                         prop.setSetter(m);
118                     }
119                 }
120             }
121         }
122 
123         return fieldMap;
124     }
125 
126     /**
127      * @return Full class name for Entity (example: package.EntityClass).
128      */
129     public String getEntityClassName ()
130     {
131         return this.entityClassName;
132     }
133 
134     /**
135      * @return Short class name (no package) for Entity (example: EntityClass).
136      */
137     public String getEntityShortName ()
138     {
139         return this.entityShortName;
140     }
141 
142     /**
143      * @return Prefix for Seam Component Names and Variables related to Entity (example: entityClass).
144      */
145     public String getEntityPrefix ()
146     {
147         return this.entityPrefix;
148     }
149     
150     /**
151      * @return Seam Component Name of the EntityHome object related to the Entity.
152      */
153     public String getEntityHome ()
154     {
155         return this.entityHome;
156     }
157 
158     /**
159      * @return Seam Component Name of the EntityQuery object related to the Entity.
160      */
161     public String getEntityQuery ()
162     {
163         return this.entityQuery;
164     }
165 
166     /**
167      * @return Collection of Properties/Fields for the Entity.
168      */
169     public Collection<CrudEntityProperty> getEntityFields ()
170     {
171         return Collections.unmodifiableCollection(this.entityFields.values());
172     }
173 
174     /**
175      * Gets the resource bundle key for translating the entity class into a localized message. 
176      * @return Typically, package.class
177      */
178     public String getMessageKey ()
179     {
180         return entityClassName;
181     }
182 }