001 package org.kuali.student.common.dictionary.service.impl;
002
003 import java.beans.BeanInfo;
004 import java.beans.IntrospectionException;
005 import java.beans.Introspector;
006 import java.beans.PropertyDescriptor;
007 import java.io.File;
008 import java.io.FileNotFoundException;
009 import java.io.FileOutputStream;
010 import java.io.IOException;
011 import java.io.OutputStream;
012 import java.lang.reflect.ParameterizedType;
013 import java.util.Date;
014 import java.util.HashSet;
015 import java.util.List;
016 import java.util.Set;
017
018 import org.kuali.student.common.dictionary.dto.FieldDefinition;
019 import org.kuali.student.common.dto.Idable;
020 import org.kuali.student.common.dto.MetaInfo;
021
022 public class DictionaryCreator
023 {
024
025 private static final String OBJECT_STRUCTURE_CLASS =
026 "objectStructureDefinition";
027 private static final String FIELD_DEFINITION_CLASS =
028 FieldDefinition.class.getSimpleName ();
029 private static final String ATTRIBUTES = "attributes";
030 private static final String NAME = "name";
031 private static final String HAS_META_DATA = "hasMetaData";
032 private static final String DATA_OBJECT_STRUCTURE = "dataObjectStructure";
033 private static final String BASE_INTEGER_REPEATING = "baseIntegerRepeating";
034 private static final String BASE_LONG_REPEATING = "baseLongRepeating";
035 private static final String BASE_DOUBLE_REPEATING = "baseDoubleRepeating";
036 private static final String BASE_FLOAT_REPEATING = "baseFloatRepeating";
037 private static final String BASE_BOOLEAN_REPEATING = "baseBooleanRepeating";
038 private static final String BASE_DATE_REPEATING = "baseDateRepeating";
039 private static final String BASE_STRING_REPEATING = "baseStringRepeating";
040 private static final String BASE_COMPLEX_REPEATING = "baseComplexRepeating";
041 private static final String BASE_INTEGER = "baseInteger";
042 private static final String BASE_LONG = "baseLong";
043 private static final String BASE_DOUBLE = "baseDouble";
044 private static final String BASE_FLOAT = "baseFloat";
045 private static final String BASE_BOOLEAN = "baseBoolean";
046 private static final String BASE_DATE = "baseDate";
047 private static final String BASE_STRING = "baseString";
048 private static final String BASE_COMPLEX = "baseComplex";
049 private static final String BASE_KUALI_ID = "baseKualiId";
050 private static final String BASE_KUALI_ORG_ID = "baseKualiOrgId";
051 private static final String BASE_KUALI_CLU_ID = "baseKualiCluId";
052 private static final String BASE_KUALI_PERSON_ID = "baseKualiPersonId";
053 private static final String BASE_KUALI_TYPE = "baseKualiType";
054 private static final String BASE_KUALI_STATE = "baseKualiState";
055 private static final String BASE_KUALI_EFFECTIVE_DATE =
056 "baseKualiEffectiveDate";
057 private static final String BASE_KUALI_EXPIRATION_DATE =
058 "baseKualiExpirationDate";
059
060
061 public void execute (Class<?> clazz, String outputFileName)
062 {
063 // Create base dictionary object structure for DTOs that map to entities
064 File file = new File (outputFileName);
065 OutputStream os;
066 try
067 {
068 os = new FileOutputStream (file);
069 }
070 catch (FileNotFoundException ex)
071 {
072 throw new IllegalArgumentException (ex);
073 }
074 StringBuffer s = new StringBuffer ();
075 addSpringHeaderOpen (s);
076
077 System.out.println (clazz.getName ());
078 addObjectStructure (clazz, s, new HashSet<Class<?>> ());
079
080 addSpringHeaderClose (s);
081 try
082 {
083 os.write (s.toString ().getBytes ());
084 }
085 catch (IOException ex)
086 {
087 throw new IllegalArgumentException (ex);
088 }
089 }
090
091 private void addObjectStructure (Class<?> clazz, StringBuffer s,
092 Set<Class<?>> processed)
093 {
094 //Don't process if processed
095 if (processed.contains (clazz))
096 {
097 return;
098 }
099 processed.add (clazz);
100
101 //Step 1, create the abstract structure
102 s.append ("\n\n<!-- " + clazz.getSimpleName () + "-->");
103 s.append ("\n<bean id=\"" + clazz.getName ()
104 + "-parent\" abstract=\"true\" parent=\"" + OBJECT_STRUCTURE_CLASS
105 + "\">");
106 addProperty (NAME, clazz.getName (), s);
107 s.append ("\n<property name=\"" + ATTRIBUTES + "\">");
108 s.append ("\n<list>");
109 BeanInfo beanInfo;
110 try
111 {
112 beanInfo = Introspector.getBeanInfo (clazz);
113 }
114 catch (IntrospectionException ex)
115 {
116 throw new IllegalArgumentException (ex);
117 }
118 boolean hasMetaData = false;
119 for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors ())
120 {
121 if ( ! MetaInfo.class.equals (pd.getPropertyType ()) && ! Class.class.equals (
122 pd.getPropertyType ()) && ! ATTRIBUTES.equals (pd.getName ()))
123 {
124 String fieldName = clazz.getSimpleName ().substring (0, 1).toLowerCase () + clazz.getSimpleName ().substring (
125 1) + "." + pd.getName ();
126 s.append ("\n<ref bean=\"" + fieldName + "\"/>");
127 }
128 else
129 {
130 hasMetaData = true;
131 }
132 }
133 s.append ("\n</list>");
134 s.append ("\n</property>");
135
136 addProperty (HAS_META_DATA, String.valueOf (hasMetaData), s);
137 s.append ("\n</bean>");
138
139 //Create the instance
140 s.append ("\n<bean id=\"" + clazz.getName () + "\" parent=\""
141 + clazz.getName () + "-parent\"/>");
142 //Step 2, loop through attributes
143 Set<Class<?>> dependantStructures = new HashSet<Class<?>> ();
144 for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors ())
145 {
146 if ( ! MetaInfo.class.equals (pd.getPropertyType ()) && ! Class.class.equals (
147 pd.getPropertyType ()) && ! ATTRIBUTES.equals (pd.getName ()))
148 {
149 dependantStructures.addAll (addField (clazz, pd, s, processed));
150 }
151 }
152 //Step 3, process all dependant object structures
153 for (Class<?> dependantClass : dependantStructures)
154 {
155 addObjectStructure (dependantClass, s, processed);
156 }
157
158 }
159
160 private Set<Class<?>> addField (Class<?> clazz, PropertyDescriptor pd,
161 StringBuffer s, Set<Class<?>> processed)
162 {
163 Set<Class<?>> dependantStructures = new HashSet<Class<?>> ();
164
165 //Create the abstract field
166 String fieldName = clazz.getSimpleName ().substring (0, 1).toLowerCase () + clazz.getSimpleName ().substring (
167 1) + "." + pd.getName ();
168 Class<?> pt = pd.getPropertyType ();
169 String parentField = FIELD_DEFINITION_CLASS;
170 boolean isComplex = false;
171 if (clazz.isAssignableFrom (Idable.class) && "id".equals (pd.getName ()))
172 {
173 parentField = BASE_KUALI_ID;
174 }
175 else if (pd.getName ().endsWith ("orgId"))
176 {
177 parentField = BASE_KUALI_ORG_ID;
178 }
179 else if (pd.getName ().endsWith ("personId"))
180 {
181 parentField = BASE_KUALI_PERSON_ID;
182 }
183 else if (pd.getName ().endsWith ("cluId"))
184 {
185 parentField = BASE_KUALI_CLU_ID;
186 }
187 else if (List.class.equals (pt))
188 {
189 try
190 {
191 pt =
192 (Class<?>) ((ParameterizedType) clazz.getDeclaredField (pd.getName ()).getGenericType ()).getActualTypeArguments ()[0];
193 }
194 catch (NoSuchFieldException ex)
195 {
196 throw new IllegalArgumentException (ex);
197 }
198 catch (SecurityException ex)
199 {
200 throw new IllegalArgumentException (ex);
201 }
202 if (int.class.equals (pt) || Integer.class.equals (pt))
203 {
204 parentField = BASE_INTEGER_REPEATING;
205 }
206 else if (long.class.equals (pt) || Long.class.equals (pt))
207 {
208 parentField = BASE_LONG_REPEATING;
209 }
210 else if (double.class.equals (pt) || Double.class.equals (pt))
211 {
212 parentField = BASE_DOUBLE_REPEATING;
213 }
214 else if (float.class.equals (pt) || Float.class.equals (pt))
215 {
216 parentField = BASE_FLOAT_REPEATING;
217 }
218 else if (boolean.class.equals (pt) || Boolean.class.equals (pt))
219 {
220 parentField = BASE_BOOLEAN_REPEATING;
221 }
222 else if (Date.class.equals (pt))
223 {
224 parentField = BASE_DATE_REPEATING;
225 }
226 else if (String.class.equals (pt))
227 {
228 parentField = BASE_STRING_REPEATING;
229 }
230 else if (List.class.equals (pt))
231 {
232 throw new RuntimeException ("Can't have a list of lists, List<List<?>> for property: "
233 + fieldName);
234 }
235 else
236 {
237 parentField = BASE_COMPLEX_REPEATING;
238 isComplex = true;
239 dependantStructures.add (pt);
240 }
241 }
242 else
243 {
244 if (int.class.equals (pt) || Integer.class.equals (pt))
245 {
246 parentField = BASE_INTEGER;
247 }
248 else if (long.class.equals (pt) || Long.class.equals (pt))
249 {
250 parentField = BASE_LONG;
251 }
252 else if (double.class.equals (pt) || Double.class.equals (pt))
253 {
254 parentField = BASE_DOUBLE;
255 }
256 else if (float.class.equals (pt) || Float.class.equals (pt))
257 {
258 parentField = BASE_FLOAT;
259 }
260 else if (boolean.class.equals (pt) || Boolean.class.equals (pt))
261 {
262 parentField = BASE_BOOLEAN;
263 }
264 else if (Date.class.equals (pt))
265 {
266 parentField = BASE_DATE;
267 }
268 else if (String.class.equals (pt))
269 {
270 parentField = BASE_STRING;
271 }
272 else
273 {
274 parentField = BASE_COMPLEX;
275 isComplex = true;
276 dependantStructures.add (pt);
277 }
278 }
279
280
281 s.append ("\n\n<bean id=\"" + fieldName
282 + "-parent\" abstract=\"true\" parent=\"" + parentField + "\">");
283 addProperty (NAME, pd.getName (), s);
284 if (isComplex)
285 {
286 addPropertyRef (DATA_OBJECT_STRUCTURE, pt.getName (), s);
287 }
288
289 s.append ("\n</bean>");
290
291 //Create the instance
292 s.append ("\n<bean id=\"" + fieldName + "\" parent=\"" + fieldName
293 + "-parent\"/>");
294
295 return dependantStructures;
296 }
297
298 private void addProperty (String propertyName, String propertyValue,
299 StringBuffer s)
300 {
301 s.append ("\n<property name=\"" + propertyName + "\" value=\"" + propertyValue
302 + "\"/>");
303 }
304
305 private static void addPropertyRef (String propertyName, String propertyValue,
306 StringBuffer s)
307 {
308 s.append ("\n<property name=\"" + propertyName + "\" ref=\"" + propertyValue
309 + "\"/>");
310 }
311
312 private void addSpringHeaderClose (StringBuffer s)
313 {
314 s.append ("\n</beans>");
315 }
316
317 public void addSpringHeaderOpen (StringBuffer s)
318 {
319 s.append ("<beans xmlns=\"http://www.springframework.org/schema/beans\""
320 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
321 + "xsi:schemaLocation=\""
322 + "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
323 + "\">");
324 s.append ("\n<import resource=\"classpath:ks-base-dictionary-context.xml\"/>");
325 }
326 }