Coverage Report - org.kuali.student.datadictionary.util.DictionaryCreator
 
Classes in this File Line Coverage Branch Coverage Complexity
DictionaryCreator
0%
0/179
0%
0/90
6.789
DictionaryCreator$1
0%
0/1
N/A
6.789
DictionaryCreator$PropertyDescriptorComparator
0%
0/29
0%
0/24
6.789
 
 1  
 /*
 2  
  * Copyright 2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 1.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl1.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.student.datadictionary.util;
 17  
 
 18  
 import java.beans.BeanInfo;
 19  
 import java.beans.IntrospectionException;
 20  
 import java.beans.Introspector;
 21  
 import java.beans.PropertyDescriptor;
 22  
 import java.io.File;
 23  
 import java.io.FileNotFoundException;
 24  
 import java.io.FileOutputStream;
 25  
 import java.io.IOException;
 26  
 import java.io.OutputStream;
 27  
 import java.util.ArrayList;
 28  
 import java.util.Arrays;
 29  
 import java.util.Collections;
 30  
 import java.util.Comparator;
 31  
 import java.util.HashSet;
 32  
 import java.util.List;
 33  
 import java.util.Set;
 34  
 import org.kuali.rice.kns.datadictionary.DataObjectEntry;
 35  
 
 36  
 import org.kuali.rice.kns.datadictionary.validation.DataType;
 37  
 
 38  0
 public class DictionaryCreator {
 39  
 
 40  
     private static String initLower(String str) {
 41  0
         if (str == null) {
 42  0
             return null;
 43  
         }
 44  0
         if (str.length() == 0) {
 45  0
             return str;
 46  
         }
 47  0
         if (str.length() == 1) {
 48  0
             return str.toLowerCase();
 49  
         }
 50  0
         return str.substring(0, 1).toLowerCase() + str.substring(1);
 51  
     }
 52  
 
 53  
     public void execute(Class<?> clazz, String outputFileName) {
 54  
         // Create base dictionary object structure for DTOs that map to entities
 55  0
         File file = new File(outputFileName);
 56  
         OutputStream os;
 57  
         try {
 58  0
             os = new FileOutputStream(file);
 59  0
         } catch (FileNotFoundException ex) {
 60  0
             throw new IllegalArgumentException(ex);
 61  0
         }
 62  0
         StringBuffer s = new StringBuffer();
 63  0
         addSpringHeaderOpen(s);
 64  
 
 65  0
         System.out.println(clazz.getName());
 66  0
         addObjectStructure(clazz, s, new HashSet<Class<?>>());
 67  
 
 68  0
         addSpringHeaderClose(s);
 69  
         try {
 70  0
             os.write(s.toString().getBytes());
 71  0
             os.close();
 72  0
         } catch (IOException ex) {
 73  0
             throw new IllegalArgumentException(ex);
 74  0
         }
 75  0
     }
 76  
 
 77  
     private void addObjectStructure(Class<?> clazz, StringBuffer s,
 78  
             Set<Class<?>> processed) {
 79  
         //Don't process if processed
 80  0
         if (processed.contains(clazz)) {
 81  0
             return;
 82  
         }
 83  0
         processed.add(clazz);
 84  
 
 85  
         BeanInfo beanInfo;
 86  
         try {
 87  0
             beanInfo = Introspector.getBeanInfo(clazz);
 88  0
         } catch (IntrospectionException ex) {
 89  0
             throw new IllegalArgumentException(ex);
 90  0
         }
 91  
 
 92  
 
 93  
         //Step 1, create the abstract structure
 94  0
         s.append("\n\n<!-- " + clazz.getSimpleName() + "-->");
 95  0
         s.append("\n<bean id=\"" + initLower(clazz.getSimpleName())
 96  
                 + "-parent\" abstract=\"true\" parent=\"" + initLower(DataObjectEntry.class.getSimpleName())
 97  
                 + "\">");
 98  0
         addProperty("name", initLower(clazz.getSimpleName()), s);
 99  0
         addProperty("objectClass", clazz.getName(), s);
 100  0
         addProperty("objectLabel", "", s);
 101  0
         addProperty("objectDescription", "", s);
 102  0
         String titleAttribute = calcTitleAttribute(clazz, beanInfo);
 103  0
         if (titleAttribute != null) {
 104  0
             addProperty("titleAttribute", titleAttribute, s);
 105  
         }
 106  0
         s.append("\n<property name=\"primaryKeys\">");
 107  0
         List<String> pks = calcPrimaryKeys(clazz, beanInfo);
 108  0
         if (pks != null && !pks.isEmpty()) {
 109  0
             s.append("\n<list>");
 110  0
             for (String pk : pks) {
 111  0
                 addValue(pk, s);
 112  
             }
 113  0
             s.append("\n</list>");
 114  
         }
 115  0
         s.append("\n</property>");
 116  0
         s.append("\n<property name=\"attributes\">");
 117  0
         s.append("\n<list>");
 118  
 
 119  0
         for (PropertyDescriptor pd : getFilteredSortedProperties(beanInfo)) {
 120  0
             String fieldName = initLower(clazz.getSimpleName() + "." + initLower(pd.getName()));
 121  0
             s.append("\n<ref bean=\"" + fieldName + "\"/>");
 122  0
         }
 123  0
         s.append("\n</list>");
 124  0
         s.append("\n</property>");
 125  0
         s.append("\n</bean>");
 126  
 
 127  
         //Create the instance
 128  0
         s.append("\n<bean id=\"" + initLower(clazz.getSimpleName()) + "\" parent=\""
 129  
                 + initLower(clazz.getSimpleName()) + "-parent\"/>");
 130  
 
 131  
         //Step 2, loop through attributes
 132  0
         Set<Class<?>> dependantStructures = new HashSet<Class<?>>();
 133  0
         for (PropertyDescriptor pd : getFilteredSortedProperties(beanInfo)) {
 134  0
             dependantStructures.addAll(addAttributeDefinition(clazz, pd, s, processed));
 135  
         }
 136  
         //Step 3, process all dependant object structures
 137  0
         for (Class<?> dependantClass : dependantStructures) {
 138  0
             addObjectStructure(dependantClass, s, processed);
 139  
         }
 140  0
     }
 141  
 
 142  
     private List<PropertyDescriptor> getFilteredSortedProperties(BeanInfo beanInfo) {
 143  0
         List<PropertyDescriptor> list = new ArrayList(beanInfo.getPropertyDescriptors().length);
 144  0
         for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
 145  0
             if (pd.getPropertyType().equals(Class.class)) {
 146  0
                 continue;
 147  
             }
 148  0
             list.add(pd);
 149  
         }
 150  0
         Collections.sort(list, new PropertyDescriptorComparator());
 151  0
         return list;
 152  
     }
 153  
 
 154  0
     private static class PropertyDescriptorComparator implements Comparator<PropertyDescriptor> {
 155  
 
 156  
         @Override
 157  
         public int compare(PropertyDescriptor o1, PropertyDescriptor o2) {
 158  0
             return calcRank(o1).compareTo(calcRank(o2));
 159  
         }
 160  
 
 161  
         private String calcRank(PropertyDescriptor pd) {
 162  
 
 163  0
             String name = pd.getName();
 164  0
             String lowerName = pd.getName().toLowerCase();
 165  0
             if (lowerName.equals("id")) {
 166  0
                 return "00" + name;
 167  
             }
 168  0
             if (lowerName.equals("key")) {
 169  0
                 return "00" + name;
 170  
             }
 171  0
             if (lowerName.equals("typekey")) {
 172  0
                 return "01" + name;
 173  
             }
 174  0
             if (lowerName.equals("statekey")) {
 175  0
                 return "02" + name;
 176  
             }
 177  0
             if (lowerName.equals("name")) {
 178  0
                 return "03" + name;
 179  
             }
 180  0
             if (lowerName.equals("descr")) {
 181  0
                 return "04" + name;
 182  
             }
 183  0
             if (lowerName.equals("effectivedate")) {
 184  0
                 return "10" + name;
 185  
             }
 186  0
             if (lowerName.equals("expirationdate")) {
 187  0
                 return "11" + name;
 188  
             }
 189  0
             if (lowerName.equals("attributes")) {
 190  0
                 return "80" + name;
 191  
             }
 192  0
             if (lowerName.equals("metainfo")) {
 193  0
                 return "90" + name;
 194  
             }
 195  0
             if (lowerName.equals("startdate")) {
 196  0
                 return "48" + name;
 197  
             }
 198  0
             if (lowerName.equals ("enddate")) {
 199  0
                 return "49" + name;
 200  
             }
 201  0
             return "50" + name;
 202  
         }
 203  
     }
 204  
 
 205  
     private String calcTitleAttribute(Class<?> clazz, BeanInfo beanInfo) {
 206  0
         for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
 207  0
             if (pd.getName().equalsIgnoreCase("name")) {
 208  0
                 return initLower(pd.getName());
 209  
             }
 210  
         }
 211  0
         for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
 212  0
             if (pd.getName().equalsIgnoreCase("title")) {
 213  0
                 return initLower(pd.getName());
 214  
             }
 215  
         }
 216  0
         for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
 217  0
             if (pd.getName().toLowerCase().endsWith("name")) {
 218  0
                 return initLower(pd.getName());
 219  
             }
 220  
         }
 221  0
         for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
 222  0
             if (pd.getName().toLowerCase().endsWith("title")) {
 223  0
                 return initLower(pd.getName());
 224  
             }
 225  
         }
 226  0
         return null;
 227  
     }
 228  
 
 229  
     private List<String> calcPrimaryKeys(Class<?> clazz, BeanInfo beanInfo) {
 230  0
         for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
 231  0
             if (pd.getName().equalsIgnoreCase("id")) {
 232  0
                 return Arrays.asList(initLower(pd.getName()));
 233  
             }
 234  
         }
 235  0
         for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
 236  0
             if (pd.getName().equalsIgnoreCase("key")) {
 237  0
                 return Arrays.asList(initLower(pd.getName()));
 238  
             }
 239  
         }
 240  0
         return null;
 241  
     }
 242  
 
 243  
     private Set<Class<?>> addAttributeDefinition(Class<?> clazz, PropertyDescriptor pd,
 244  
             StringBuffer s, Set<Class<?>> processed) {
 245  0
         Set<Class<?>> dependantStructures = new HashSet<Class<?>>();
 246  
 
 247  
         //Create the abstract field
 248  0
         String name = clazz.getSimpleName().substring(0, 1).toLowerCase() + clazz.getSimpleName().substring(
 249  
                 1) + "." + pd.getName();
 250  0
         Class<?> actualClass = Bean2DictionaryConverter.calcActualClass(clazz, pd);
 251  0
         DataType dt = calcDataType(clazz, pd);
 252  0
         String parentField = calcBaseKualiType(actualClass, pd, dt);
 253  
 
 254  0
         s.append("\n\n<bean id=\"" + name
 255  
                 + "-parent\" abstract=\"true\" parent=\"" + parentField + "\">");
 256  0
         addProperty("name", initLower(pd.getName()), s);
 257  0
         if (isList(pd)) {
 258  0
             addProperty("maxOccurs", "" + DictionaryConstants.UNBOUNDED, s);
 259  
         }
 260  0
         s.append("\n</bean>");
 261  
 
 262  
         //Create the instance
 263  0
         s.append("\n<bean id=\"" + name + "\" parent=\"" + name
 264  
                 + "-parent\"/>");
 265  0
         return dependantStructures;
 266  
     }
 267  
 
 268  
     private DataType calcDataType(Class<?> clazz, PropertyDescriptor pd) {
 269  0
         Class<?> actualClass = Bean2DictionaryConverter.calcActualClass(clazz, pd);
 270  0
         DataType dataType = Bean2DictionaryConverter.calcDataType(actualClass);
 271  0
         return dataType;
 272  
     }
 273  
 
 274  
     private boolean isList(PropertyDescriptor pd) {
 275  0
         if (pd.getPropertyType().equals(List.class)) {
 276  0
             return true;
 277  
         }
 278  0
         return false;
 279  
     }
 280  
 
 281  
     private boolean isComplex(Class<?> clazz, PropertyDescriptor pd) {
 282  0
         return isComplex(calcDataType(clazz, pd));
 283  
     }
 284  
 
 285  
     private boolean isComplex(DataType dt) {
 286  0
         if (dt.equals(DataType.COMPLEX)) {
 287  0
             return true;
 288  
         }
 289  0
         return false;
 290  
     }
 291  
 
 292  
     private String calcBaseKualiType(Class<?> clazz, PropertyDescriptor pd, DataType dt) {
 293  
 
 294  0
         String name = pd.getName();
 295  0
         String lowerName = pd.getName().toLowerCase();
 296  0
         if (lowerName.equals("id")) {
 297  0
             return "baseKualiId";
 298  
         }
 299  0
         if (lowerName.equals("key")) {
 300  0
             return "baseKualiKey";
 301  
         }
 302  0
         if (lowerName.equals("typeKey")) {
 303  0
             return "baseKualiTypeKey";
 304  
         }
 305  0
         if (lowerName.equals("stateKey")) {
 306  0
             return "baseKualiStateKey";
 307  
         }
 308  0
         if (lowerName.equals("effectivedate")) {
 309  0
             return "baseKualiEffectiveDate";
 310  
         }
 311  0
         if (lowerName.equals("expirationdate")) {
 312  0
             return "baseKualiExpirationDate";
 313  
         }
 314  0
         if (lowerName.endsWith("orgid")) {
 315  0
             return "baseKualiOrgId";
 316  
         }
 317  0
         if (lowerName.endsWith("personid")) {
 318  0
             return "baseKualiPersonId";
 319  
         }
 320  0
         if (lowerName.endsWith("principalid")) {
 321  0
             return "baseKualiPrincipalId";
 322  
         }
 323  0
         if (lowerName.endsWith("cluid")) {
 324  0
             return "baseKualiCluId";
 325  
         }
 326  0
         if (lowerName.endsWith("luiid")) {
 327  0
             return "baseKualiCluId";
 328  
         }
 329  0
         if (lowerName.endsWith("code")) {
 330  0
             return "baseKualiCode";
 331  
         }
 332  0
         switch (dt) {
 333  
             case STRING:
 334  0
                 return "baseKualiString";
 335  
             case DATE:
 336  0
                 return "baseKualiDateTime";
 337  
             case TRUNCATED_DATE:
 338  0
                 return "baseKualiDate";
 339  
             case BOOLEAN:
 340  0
                 return "baseKualiBoolean";
 341  
             case INTEGER:
 342  
             case LONG:
 343  0
                 return "baseKualiInteger";
 344  
             case FLOAT:
 345  
             case DOUBLE:
 346  0
                 return "baseKualiCurrency";
 347  
             case COMPLEX:
 348  0
                 return "baseKualiComplex";
 349  
             default:
 350  0
                 return "baseKualiString";
 351  
         }
 352  
     }
 353  
 
 354  
     private void addValue(String value, StringBuffer s) {
 355  0
         s.append("\n<value>" + value + "</value>");
 356  0
     }
 357  
 
 358  
     private void addProperty(String propertyName, String propertyValue,
 359  
             StringBuffer s) {
 360  0
         s.append("\n<property name=\"" + propertyName + "\" value=\"" + propertyValue
 361  
                 + "\"/>");
 362  0
     }
 363  
 
 364  
     private static void addPropertyRef(String propertyName, String propertyValue,
 365  
             StringBuffer s) {
 366  0
         s.append("\n<property name=\"" + propertyName + "\" ref=\"" + propertyValue
 367  
                 + "\"/>");
 368  0
     }
 369  
 
 370  
     private void addSpringHeaderClose(StringBuffer s) {
 371  0
         s.append("\n</beans>").append("\n");
 372  0
     }
 373  
 
 374  
     private void addSpringHeaderOpen(StringBuffer s) {
 375  0
         s.append("<!--").append("\n");
 376  0
         s.append(" Copyright 2011 The Kuali Foundation").append("\n");
 377  0
         s.append("").append("\n");
 378  0
         s.append(" Licensed under the Educational Community License, Version 2.0 (the \"License\");").append("\n");
 379  0
         s.append(" you may not use this file except in compliance with the License.").append("\n");
 380  0
         s.append(" You may obtain a copy of the License at").append("\n");
 381  0
         s.append("").append("\n");
 382  0
         s.append(" http://www.opensource.org/licenses/ecl2.php").append("\n");
 383  0
         s.append("").append("\n");
 384  0
         s.append(" Unless required by applicable law or agreed to in writing, software").append("\n");
 385  0
         s.append(" distributed under the License is distributed on an \"AS IS\" BASIS,").append("\n");
 386  0
         s.append(" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.").append("\n");
 387  0
         s.append(" See the License for the specific language governing permissions and").append("\n");
 388  0
         s.append(" limitations under the License.").append("\n");
 389  0
         s.append("-->").append("\n");
 390  0
         s.append("<beans xmlns=\"http://www.springframework.org/schema/beans\"").append("\n");
 391  0
         s.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"").append("\n");
 392  0
         s.append("xsi:schemaLocation=\"").append("\n");
 393  0
         s.append("http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd").append("\n");
 394  0
         s.append("\">").append("\n");
 395  0
         s.append("\n<import resource=\"classpath:ks-base-dictionary.xml\"/>");
 396  0
     }
 397  
 }
 398