1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.datadictionary;
17
18 import org.apache.commons.beanutils.PropertyUtils;
19 import org.apache.commons.collections.ListUtils;
20 import org.apache.commons.lang.ArrayUtils;
21 import org.apache.commons.lang.ClassUtils;
22 import org.apache.commons.lang.StringUtils;
23 import org.kuali.rice.core.api.config.property.ConfigContext;
24 import org.kuali.rice.core.api.util.ClassLoaderUtils;
25 import org.kuali.rice.krad.data.provider.annotation.UifAutoCreateViewType;
26 import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
27 import org.kuali.rice.krad.datadictionary.exception.CompletionException;
28 import org.kuali.rice.krad.datadictionary.parse.StringListConverter;
29 import org.kuali.rice.krad.datadictionary.parse.StringMapConverter;
30 import org.kuali.rice.krad.datadictionary.uif.ComponentBeanPostProcessor;
31 import org.kuali.rice.krad.datadictionary.uif.UifBeanFactoryPostProcessor;
32 import org.kuali.rice.krad.datadictionary.uif.UifDictionaryIndex;
33 import org.kuali.rice.krad.datadictionary.validator.ErrorReport;
34 import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
35 import org.kuali.rice.krad.datadictionary.validator.Validator;
36 import org.kuali.rice.krad.lookup.LookupView;
37 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
38 import org.kuali.rice.krad.service.LegacyDataAdapter;
39 import org.kuali.rice.krad.uif.UifConstants;
40 import org.kuali.rice.krad.uif.UifConstants.ViewType;
41 import org.kuali.rice.krad.uif.util.ComponentFactory;
42 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
43 import org.kuali.rice.krad.uif.view.InquiryView;
44 import org.kuali.rice.krad.uif.view.View;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.beans.PropertyValue;
48 import org.springframework.beans.PropertyValues;
49 import org.springframework.beans.factory.config.BeanDefinition;
50 import org.springframework.beans.factory.config.BeanPostProcessor;
51 import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
52 import org.springframework.beans.factory.support.ChildBeanDefinition;
53 import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
54 import org.springframework.context.expression.StandardBeanExpressionResolver;
55 import org.springframework.core.convert.support.GenericConversionService;
56 import org.springframework.core.io.DefaultResourceLoader;
57 import org.springframework.core.io.Resource;
58 import org.springframework.util.StopWatch;
59
60 import java.beans.PropertyDescriptor;
61 import java.io.File;
62 import java.io.IOException;
63 import java.util.ArrayList;
64 import java.util.Arrays;
65 import java.util.Collection;
66 import java.util.HashMap;
67 import java.util.List;
68 import java.util.Map;
69 import java.util.Set;
70 import java.util.TreeMap;
71
72
73
74
75
76
77
78 public class DataDictionary {
79
80 private static final Logger LOG = LoggerFactory.getLogger(DataDictionary.class);
81
82 protected static boolean validateEBOs = true;
83
84 protected DefaultListableBeanFactory ddBeans = new DefaultListableBeanFactory();
85 protected XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ddBeans);
86
87 protected DataDictionaryIndex ddIndex = new DataDictionaryIndex(ddBeans);
88 protected UifDictionaryIndex uifIndex = new UifDictionaryIndex(ddBeans);
89
90 protected DataDictionaryMapper ddMapper = new DataDictionaryIndexMapper();
91
92 protected Map<String, List<String>> moduleDictionaryFiles = new HashMap<String, List<String>>();
93 protected List<String> moduleLoadOrder = new ArrayList<String>();
94
95 protected ArrayList<String> beanValidationFiles = new ArrayList<String>();
96
97 public static LegacyDataAdapter legacyDataAdapter;
98
99 protected transient StopWatch timer;
100
101
102
103
104
105
106
107
108 public void parseDataDictionaryConfigurationFiles(boolean allowConcurrentValidation) {
109 timer = new StopWatch("DD Processing");
110 setupProcessor(ddBeans);
111
112 loadDictionaryBeans(ddBeans, moduleDictionaryFiles, ddIndex, beanValidationFiles);
113
114 performDictionaryPostProcessing(allowConcurrentValidation);
115 }
116
117
118
119
120
121
122 public static void setupProcessor(DefaultListableBeanFactory beans) {
123 try {
124
125 BeanPostProcessor idPostProcessor = ComponentBeanPostProcessor.class.newInstance();
126 beans.addBeanPostProcessor(idPostProcessor);
127 beans.setBeanExpressionResolver(new StandardBeanExpressionResolver());
128
129
130 GenericConversionService conversionService = new GenericConversionService();
131 conversionService.addConverter(new StringMapConverter());
132 conversionService.addConverter(new StringListConverter());
133
134 beans.setConversionService(conversionService);
135 } catch (Exception e1) {
136 throw new DataDictionaryException("Cannot create component decorator post processor: " + e1.getMessage(),
137 e1);
138 }
139 }
140
141
142
143
144
145
146
147
148
149 public void loadDictionaryBeans(DefaultListableBeanFactory beans,
150 Map<String, List<String>> moduleDictionaryFiles, DataDictionaryIndex index,
151 ArrayList<String> validationFiles) {
152
153 timer.start("XML File Loading");
154 LOG.info("Starting DD XML File Load");
155
156 List<String> allBeanNames = new ArrayList<String>();
157 for (String namespaceCode : moduleLoadOrder) {
158 LOG.info( "Processing Module: " + namespaceCode);
159 List<String> moduleDictionaryLocations = moduleDictionaryFiles.get(namespaceCode);
160 if ( LOG.isDebugEnabled() ) {
161 LOG.debug("DD Locations in Module: " + moduleDictionaryLocations);
162 }
163
164 if (moduleDictionaryLocations == null) {
165 continue;
166 }
167
168 XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(beans);
169
170 String configFileLocationsArray[] = new String[moduleDictionaryLocations.size()];
171 configFileLocationsArray = moduleDictionaryLocations.toArray(configFileLocationsArray);
172 for (int i = 0; i < configFileLocationsArray.length; i++) {
173 validationFiles.add(configFileLocationsArray[i]);
174 }
175
176 try {
177 xmlReader.loadBeanDefinitions(configFileLocationsArray);
178
179
180
181 List<String> addedBeanNames = Arrays.asList(beans.getBeanDefinitionNames());
182 addedBeanNames = ListUtils.removeAll(addedBeanNames, allBeanNames);
183 index.addBeanNamesToNamespace(namespaceCode, addedBeanNames);
184
185 allBeanNames.addAll(addedBeanNames);
186 } catch (Exception e) {
187 throw new DataDictionaryException("Error loading bean definitions: " + e.getLocalizedMessage(),e);
188 }
189 }
190
191 LOG.info("Completed DD XML File Load");
192 timer.stop();
193 }
194
195
196
197
198
199
200
201 public void performDictionaryPostProcessing(boolean allowConcurrentValidation) {
202 LOG.info("Starting Data Dictionary Post Processing");
203
204 timer.start("Spring Post Processing");
205 PropertyPlaceholderConfigurer propertyPlaceholderConfigurer = new PropertyPlaceholderConfigurer();
206 propertyPlaceholderConfigurer.setProperties(ConfigContext.getCurrentContextConfig().getProperties());
207 propertyPlaceholderConfigurer.postProcessBeanFactory(ddBeans);
208
209 DictionaryBeanFactoryPostProcessor dictionaryBeanPostProcessor =
210 new DictionaryBeanFactoryPostProcessor(DataDictionary.this, ddBeans);
211 dictionaryBeanPostProcessor.postProcessBeanFactory();
212 timer.stop();
213
214
215 timer.start("UIF Post Processing");
216 UifBeanFactoryPostProcessor factoryPostProcessor = new UifBeanFactoryPostProcessor();
217 factoryPostProcessor.postProcessBeanFactory(ddBeans);
218 timer.stop();
219
220 timer.start("Instantiating DD Beans");
221 ddBeans.preInstantiateSingletons();
222 timer.stop();
223
224
225
226
227 timer.start("DD Post Processing");
228 for (DataObjectEntry entry : ddBeans.getBeansOfType(DataObjectEntry.class).values()) {
229 entry.dataDictionaryPostProcessing();
230 }
231 for (DocumentEntry entry : ddBeans.getBeansOfType(DocumentEntry.class).values()) {
232 entry.dataDictionaryPostProcessing();
233 }
234 timer.stop();
235
236 timer.start("Data Dictionary Indexing");
237 ddIndex.run();
238 timer.stop();
239
240
241 timer.start("UIF Defaulting");
242 generateMissingInquiryDefinitions();
243 generateMissingLookupDefinitions();
244 timer.stop();
245
246 timer.start("UIF Indexing");
247 uifIndex.run();
248 timer.stop();
249
250 LOG.info("Completed Data Dictionary Post Processing");
251 }
252
253 protected void generateMissingInquiryDefinitions() {
254 Collection<InquiryView> inquiryViewBeans = ddBeans.getBeansOfType(InquiryView.class).values();
255
256 Map<Class<?>,InquiryView> defaultViewsByDataObjectClass = new HashMap<Class<?>, InquiryView>();
257 for ( InquiryView view : inquiryViewBeans ) {
258 if ( view.getViewName().equals(UifConstants.DEFAULT_VIEW_NAME) ) {
259 defaultViewsByDataObjectClass.put(view.getDataObjectClassName(), view);
260 }
261 }
262 for (DataObjectEntry entry : ddBeans.getBeansOfType(DataObjectEntry.class).values()) {
263
264 if ( defaultViewsByDataObjectClass.containsKey(entry.getDataObjectClass())) {
265 continue;
266 }
267
268 if ( entry.getDataObjectMetadata() == null ) {
269 continue;
270 }
271 if ( !entry.getDataObjectMetadata().shouldAutoCreateUifViewOfType(UifAutoCreateViewType.INQUIRY)) {
272 continue;
273 }
274
275 if ( LOG.isInfoEnabled() ) {
276 LOG.info( "Generating Inquiry View for : " + entry.getDataObjectClass() );
277 }
278 String inquiryBeanName = entry.getDataObjectClass().getSimpleName()+"-InquiryView-default";
279
280 InquiryView inquiryView = KRADServiceLocatorWeb.getUifDefaultingService().deriveInquiryViewFromMetadata(entry);
281 inquiryView.setId(inquiryBeanName);
282 inquiryView.setViewName(UifConstants.DEFAULT_VIEW_NAME);
283
284 ChildBeanDefinition inquiryBean = new ChildBeanDefinition("Uif-InquiryView");
285 inquiryBean.setScope(BeanDefinition.SCOPE_SINGLETON);
286 inquiryBean.setAttribute("dataObjectClassName", inquiryView.getDataObjectClassName());
287 inquiryBean.getPropertyValues().add("dataObjectClassName", inquiryView.getDataObjectClassName().getName());
288 inquiryBean.setResourceDescription("Autogenerated From Metadata");
289 ddBeans.registerBeanDefinition(inquiryBeanName, inquiryBean);
290 ddBeans.registerSingleton(inquiryBeanName, inquiryView);
291 }
292 }
293
294 protected void generateMissingLookupDefinitions() {
295 Collection<LookupView> lookupViewBeans = ddBeans.getBeansOfType(LookupView.class).values();
296
297 Map<Class<?>,LookupView> defaultViewsByDataObjectClass = new HashMap<Class<?>, LookupView>();
298 for ( LookupView view : lookupViewBeans ) {
299 if ( view.getViewName().equals(UifConstants.DEFAULT_VIEW_NAME) ) {
300 defaultViewsByDataObjectClass.put(view.getDataObjectClass(), view);
301 }
302 }
303 for (DataObjectEntry entry : ddBeans.getBeansOfType(DataObjectEntry.class).values()) {
304
305 if ( defaultViewsByDataObjectClass.containsKey(entry.getDataObjectClass())) {
306 continue;
307 }
308
309 if ( entry.getDataObjectMetadata() == null ) {
310 continue;
311 }
312 if ( !entry.getDataObjectMetadata().shouldAutoCreateUifViewOfType(UifAutoCreateViewType.LOOKUP)) {
313 continue;
314 }
315
316 if ( LOG.isInfoEnabled() ) {
317 LOG.info( "Generating Lookup View for : " + entry.getDataObjectClass() );
318 }
319 String lookupBeanName = entry.getDataObjectClass().getSimpleName()+"-LookupView-default";
320
321 LookupView lookupView = KRADServiceLocatorWeb.getUifDefaultingService().deriveLookupViewFromMetadata(entry);
322 lookupView.setId(lookupBeanName);
323 lookupView.setViewName(UifConstants.DEFAULT_VIEW_NAME);
324
325 ChildBeanDefinition lookupBean = new ChildBeanDefinition(ComponentFactory.LOOKUP_VIEW);
326 lookupBean.setScope(BeanDefinition.SCOPE_SINGLETON);
327 lookupBean.setAttribute("dataObjectClassName", lookupView.getDataObjectClass());
328 lookupBean.getPropertyValues().add("dataObjectClassName", lookupView.getDataObjectClass().getName());
329 lookupBean.setResourceDescription("Autogenerated From Metadata");
330 ddBeans.registerBeanDefinition(lookupBeanName, lookupBean);
331 ddBeans.registerSingleton(lookupBeanName, lookupView);
332 }
333 }
334
335 public void validateDD(boolean validateEbos) {
336 timer.start("Validation");
337 DataDictionary.validateEBOs = validateEbos;
338
339 Validator.resetErrorReport();
340
341 Map<String, DataObjectEntry> doBeans = ddBeans.getBeansOfType(DataObjectEntry.class);
342 for (DataObjectEntry entry : doBeans.values()) {
343 entry.completeValidation(new ValidationTrace());
344 }
345
346 Map<String, DocumentEntry> docBeans = ddBeans.getBeansOfType(DocumentEntry.class);
347 for (DocumentEntry entry : docBeans.values()) {
348 entry.completeValidation(new ValidationTrace());
349 }
350
351 List<ErrorReport> errorReports = Validator.getErrorReports();
352 if (!errorReports.isEmpty()) {
353 boolean hasErrors = hasErrors(errorReports);
354 String errorReport = produceErrorReport(errorReports, hasErrors);
355 if (hasErrors) {
356 String message = "Errors during DD validation, failing validation.\n" + errorReport;
357 throw new DataDictionaryException(message);
358 } else {
359 String message = "Warnings during DD validation.\n" + errorReport;
360 LOG.warn(message);
361 }
362 }
363
364 timer.stop();
365 }
366
367 private boolean hasErrors(List<ErrorReport> errorReports) {
368 for (ErrorReport err : errorReports) {
369 if (err.isError()) {
370 return true;
371 }
372 }
373 return false;
374 }
375
376 protected String produceErrorReport(List<ErrorReport> errorReports, boolean hasErrors) {
377 StringBuilder builder = new StringBuilder();
378 builder.append("***********************************************************\n");
379 if (hasErrors) {
380 builder.append("ERRORS REPORTED UPON DATA DICTIONARY VALIDATION\n");
381 } else {
382 builder.append("WARNINGS REPORTED UPON DATA DICTIONARY VALIDATION\n");
383 }
384 builder.append("***********************************************************\n");
385 for (ErrorReport report : errorReports) {
386 builder.append(report.errorMessage()).append("\n");
387 }
388 return builder.toString();
389 }
390
391 public void validateDD() {
392 validateDD(true);
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408 public void addConfigFileLocation(String namespaceCode, String location) throws IOException {
409
410 if (!moduleLoadOrder.contains(namespaceCode)) {
411 moduleLoadOrder.add(namespaceCode);
412 }
413
414 indexSource(namespaceCode, location);
415 }
416
417
418
419
420
421
422
423
424 protected void indexSource(String namespaceCode, String sourceName) throws IOException {
425 if (sourceName == null) {
426 throw new DataDictionaryException("Source Name given is null");
427 }
428
429 if (!sourceName.endsWith(".xml")) {
430 Resource resource = getFileResource(sourceName);
431 if (resource.exists()) {
432 try {
433 indexSource(namespaceCode, resource.getFile());
434 } catch (IOException e) {
435
436
437 LOG.debug("Skipped existing resource without absolute file path");
438 }
439 } else {
440 LOG.warn("Could not find " + sourceName);
441 throw new DataDictionaryException("DD Resource " + sourceName + " not found");
442 }
443 } else {
444 if (LOG.isDebugEnabled()) {
445 LOG.debug("adding sourceName " + sourceName + " ");
446 }
447
448 Resource resource = getFileResource(sourceName);
449 if (!resource.exists()) {
450 throw new DataDictionaryException("DD Resource " + sourceName + " not found");
451 }
452
453 addModuleDictionaryFile(namespaceCode, sourceName);
454 }
455 }
456
457 protected Resource getFileResource(String sourceName) {
458 DefaultResourceLoader resourceLoader = new DefaultResourceLoader(ClassLoaderUtils.getDefaultClassLoader());
459
460 return resourceLoader.getResource(sourceName);
461 }
462
463 protected void indexSource(String namespaceCode, File dir) {
464 for (File file : dir.listFiles()) {
465 if (file.isDirectory()) {
466 indexSource(namespaceCode, file);
467 } else if (file.getName().endsWith(".xml")) {
468 addModuleDictionaryFile(namespaceCode, "file:" + file.getAbsolutePath());
469 } else {
470 if (LOG.isDebugEnabled()) {
471 LOG.debug("Skipping non xml file " + file.getAbsolutePath() + " in DD load");
472 }
473 }
474 }
475 }
476
477
478
479
480
481
482
483 protected void addModuleDictionaryFile(String namespaceCode, String location) {
484 List<String> moduleFileLocations = new ArrayList<String>();
485 if (moduleDictionaryFiles.containsKey(namespaceCode)) {
486 moduleFileLocations = moduleDictionaryFiles.get(namespaceCode);
487 }
488 moduleFileLocations.add(location);
489
490 moduleDictionaryFiles.put(namespaceCode, moduleFileLocations);
491 }
492
493
494
495
496
497
498
499
500 public Map<String, List<String>> getModuleDictionaryFiles() {
501 return moduleDictionaryFiles;
502 }
503
504
505
506
507
508
509 public void setModuleDictionaryFiles(Map<String, List<String>> moduleDictionaryFiles) {
510 this.moduleDictionaryFiles = moduleDictionaryFiles;
511 }
512
513
514
515
516
517
518
519
520
521
522
523 public List<String> getModuleLoadOrder() {
524 return moduleLoadOrder;
525 }
526
527
528
529
530
531
532 public void setModuleLoadOrder(List<String> moduleLoadOrder) {
533 this.moduleLoadOrder = moduleLoadOrder;
534 }
535
536
537
538
539
540
541 public void setDataDictionaryMapper(DataDictionaryMapper mapper) {
542 this.ddMapper = mapper;
543 }
544
545
546
547
548
549 @Deprecated
550 public BusinessObjectEntry getBusinessObjectEntry(String className) {
551 return ddMapper.getBusinessObjectEntry(ddIndex, className);
552 }
553
554
555
556
557
558 public DataObjectEntry getDataObjectEntry(String className) {
559 return ddMapper.getDataObjectEntry(ddIndex, className);
560 }
561
562
563
564
565
566
567
568 public BusinessObjectEntry getBusinessObjectEntryForConcreteClass(String className) {
569 return ddMapper.getBusinessObjectEntryForConcreteClass(ddIndex, className);
570 }
571
572
573
574
575 public List<String> getBusinessObjectClassNames() {
576 return ddMapper.getBusinessObjectClassNames(ddIndex);
577 }
578
579
580
581
582 public Map<String, BusinessObjectEntry> getBusinessObjectEntries() {
583 return ddMapper.getBusinessObjectEntries(ddIndex);
584 }
585
586 public Map<String, DataObjectEntry> getDataObjectEntries() {
587 return ddMapper.getDataObjectEntries(ddIndex);
588 }
589
590
591
592
593
594
595 public DataDictionaryEntry getDictionaryObjectEntry(String className) {
596 return ddMapper.getDictionaryObjectEntry(ddIndex, className);
597 }
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614 public DocumentEntry getDocumentEntry(String documentTypeDDKey) {
615 return ddMapper.getDocumentEntry(ddIndex, documentTypeDDKey);
616 }
617
618
619
620
621
622
623
624
625
626
627
628 public MaintenanceDocumentEntry getMaintenanceDocumentEntryForBusinessObjectClass(Class<?> businessObjectClass) {
629 return ddMapper.getMaintenanceDocumentEntryForBusinessObjectClass(ddIndex, businessObjectClass);
630 }
631
632 public Map<String, DocumentEntry> getDocumentEntries() {
633 return ddMapper.getDocumentEntries(ddIndex);
634 }
635
636
637
638
639
640
641
642 public View getViewById(String viewId) {
643 return ddMapper.getViewById(uifIndex, viewId);
644 }
645
646
647
648
649
650
651
652
653 public View getImmutableViewById(String viewId) {
654 return ddMapper.getImmutableViewById(uifIndex, viewId);
655 }
656
657
658
659
660
661
662
663
664
665
666 public View getViewByTypeIndex(ViewType viewTypeName, Map<String, String> indexKey) {
667 return ddMapper.getViewByTypeIndex(uifIndex, viewTypeName, indexKey);
668 }
669
670
671
672
673
674
675
676
677
678
679 public String getViewIdByTypeIndex(ViewType viewTypeName, Map<String, String> indexKey) {
680 return ddMapper.getViewIdByTypeIndex(uifIndex, viewTypeName, indexKey);
681 }
682
683
684
685
686
687
688
689
690
691
692 public boolean viewByTypeExist(ViewType viewTypeName, Map<String, String> indexKey) {
693 return ddMapper.viewByTypeExist(uifIndex, viewTypeName, indexKey);
694 }
695
696
697
698
699
700
701
702
703
704 public List<View> getViewsForType(ViewType viewTypeName) {
705 return ddMapper.getViewsForType(uifIndex, viewTypeName);
706 }
707
708
709
710
711
712
713
714 public Object getDictionaryBean(final String beanName) {
715 return ddBeans.getBean(beanName);
716 }
717
718
719
720
721
722
723
724 public boolean containsDictionaryBean(String id) {
725 return ddBeans.containsBean(id);
726 }
727
728
729
730
731
732
733
734 public Object getDictionaryPrototype(final String beanName) {
735 if (!ddBeans.isPrototype(beanName)) {
736 throw new IllegalArgumentException("Bean name " + beanName
737 + " doesn't refer to a prototype bean in the data dictionary");
738 }
739
740 return getDictionaryBean(beanName);
741 }
742
743
744
745
746
747
748
749
750
751 public Object getDictionaryBeanProperty(String beanName, String propertyName) {
752 Object bean = ddBeans.getSingleton(beanName);
753 if (bean != null) {
754 return ObjectPropertyUtils.getPropertyValue(bean, propertyName);
755 }
756
757 BeanDefinition beanDefinition = ddBeans.getMergedBeanDefinition(beanName);
758
759 if (beanDefinition == null) {
760 throw new RuntimeException("Unable to get bean for bean name: " + beanName);
761 }
762
763 PropertyValues pvs = beanDefinition.getPropertyValues();
764 if (pvs.contains(propertyName)) {
765 PropertyValue propertyValue = pvs.getPropertyValue(propertyName);
766
767 Object value;
768 if (propertyValue.isConverted()) {
769 value = propertyValue.getConvertedValue();
770 } else {
771 value = propertyValue.getValue();
772 }
773
774 return value;
775 }
776
777 return null;
778 }
779
780
781
782
783
784
785
786
787
788
789
790
791 public PropertyValues getViewPropertiesById(String viewId) {
792 return ddMapper.getViewPropertiesById(uifIndex, viewId);
793 }
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809 public PropertyValues getViewPropertiesByType(ViewType viewTypeName, Map<String, String> indexKey) {
810 return ddMapper.getViewPropertiesByType(uifIndex, viewTypeName, indexKey);
811 }
812
813
814
815
816
817
818
819 public List<String> getBeanNamesForNamespace(String namespaceCode) {
820 List<String> namespaceBeans = new ArrayList<String>();
821
822 Map<String, List<String>> dictionaryBeansByNamespace = ddIndex.getDictionaryBeansByNamespace();
823 if (dictionaryBeansByNamespace.containsKey(namespaceCode)) {
824 namespaceBeans = dictionaryBeansByNamespace.get(namespaceCode);
825 }
826
827 return namespaceBeans;
828 }
829
830
831
832
833
834
835
836 public String getNamespaceForBeanDefinition(String beanName) {
837 String beanNamespace = null;
838
839 Map<String, List<String>> dictionaryBeansByNamespace = ddIndex.getDictionaryBeansByNamespace();
840 for (Map.Entry<String, List<String>> moduleDefinitions : dictionaryBeansByNamespace.entrySet()) {
841 List<String> namespaceBeans = moduleDefinitions.getValue();
842 if (namespaceBeans.contains(beanName)) {
843 beanNamespace = moduleDefinitions.getKey();
844 break;
845 }
846 }
847
848 return beanNamespace;
849 }
850
851
852
853
854
855
856
857 public static boolean isPropertyOf(Class targetClass, String propertyName) {
858 if (targetClass == null) {
859 throw new IllegalArgumentException("invalid (null) targetClass");
860 }
861 if (StringUtils.isBlank(propertyName)) {
862 throw new IllegalArgumentException("invalid (blank) propertyName");
863 }
864 try {
865 PropertyDescriptor propertyDescriptor = buildReadDescriptor(targetClass, propertyName);
866
867 return propertyDescriptor != null;
868 } catch ( Exception ex ) {
869 LOG.error( "Exception while obtaining property descriptor for " + targetClass.getName() + "." + propertyName, ex );
870 return false;
871 }
872 }
873
874
875
876
877
878
879
880 public static boolean isCollectionPropertyOf(Class targetClass, String propertyName) {
881 boolean isCollectionPropertyOf = false;
882
883 PropertyDescriptor propertyDescriptor = buildReadDescriptor(targetClass, propertyName);
884 if (propertyDescriptor != null) {
885 Class clazz = propertyDescriptor.getPropertyType();
886
887 if ((clazz != null) && Collection.class.isAssignableFrom(clazz)) {
888 isCollectionPropertyOf = true;
889 }
890 }
891
892 return isCollectionPropertyOf;
893 }
894
895 public static LegacyDataAdapter getLegacyDataAdapter() {
896 if (legacyDataAdapter == null) {
897 legacyDataAdapter = KRADServiceLocatorWeb.getLegacyDataAdapter();
898 }
899 return legacyDataAdapter;
900 }
901
902
903
904
905
906
907
908
909
910
911 public static Class getAttributeClass(Class boClass, String attributeName) {
912
913
914 if (!isPropertyOf(boClass, attributeName)) {
915 throw new AttributeValidationException(
916 "unable to find attribute '" + attributeName + "' in rootClass '" + boClass.getName() + "'");
917 }
918
919
920
921
922 if (boClass.isInterface()) {
923 return getAttributeClassWhenBOIsInterface(boClass, attributeName);
924 } else {
925 return getAttributeClassWhenBOIsClass(boClass, attributeName);
926 }
927
928 }
929
930
931
932
933
934
935
936
937 private static Class<?> getAttributeClassWhenBOIsClass(Class<?> boClass, String attributeName) {
938 Object boInstance;
939 try {
940
941
942 if (boClass.isPrimitive()) {
943 boClass = ClassUtils.primitiveToWrapper(boClass);
944 }
945
946 boInstance = boClass.newInstance();
947 } catch (Exception e) {
948 throw new RuntimeException("Unable to instantiate Data Object: " + boClass, e);
949 }
950
951
952 try {
953 return getLegacyDataAdapter().getPropertyType(boInstance, attributeName);
954 } catch (Exception e) {
955 throw new RuntimeException(
956 "Unable to determine property type for: " + boClass.getName() + "." + attributeName, e);
957 }
958 }
959
960
961
962
963
964
965
966
967
968
969 private static Class<?> getAttributeClassWhenBOIsInterface(Class<?> boClass, String attributeName) {
970 if (boClass == null) {
971 throw new IllegalArgumentException("invalid (null) boClass");
972 }
973 if (StringUtils.isBlank(attributeName)) {
974 throw new IllegalArgumentException("invalid (blank) attributeName");
975 }
976
977 PropertyDescriptor propertyDescriptor = null;
978
979 String[] intermediateProperties = attributeName.split("\\.");
980 int lastLevel = intermediateProperties.length - 1;
981 Class currentClass = boClass;
982
983 for (int i = 0; i <= lastLevel; ++i) {
984
985 String currentPropertyName = intermediateProperties[i];
986 propertyDescriptor = buildSimpleReadDescriptor(currentClass, currentPropertyName);
987
988 if (propertyDescriptor != null) {
989
990 Class propertyType = propertyDescriptor.getPropertyType();
991 if (getLegacyDataAdapter().isExtensionAttribute(currentClass, currentPropertyName, propertyType)) {
992 propertyType = getLegacyDataAdapter().getExtensionAttributeClass(currentClass, currentPropertyName);
993 }
994 if (Collection.class.isAssignableFrom(propertyType)) {
995
996 throw new AttributeValidationException(
997 "Can't determine the Class of Collection elements because when the business object is an (possibly ExternalizableBusinessObject) interface.");
998 } else {
999 currentClass = propertyType;
1000 }
1001 } else {
1002 throw new AttributeValidationException(
1003 "Can't find getter method of " + boClass.getName() + " for property " + attributeName);
1004 }
1005 }
1006 return currentClass;
1007 }
1008
1009
1010
1011
1012
1013
1014
1015
1016 public static Class getCollectionElementClass(Class boClass, String collectionName) {
1017 if (boClass == null) {
1018 throw new IllegalArgumentException("invalid (null) boClass");
1019 }
1020 if (StringUtils.isBlank(collectionName)) {
1021 throw new IllegalArgumentException("invalid (blank) collectionName");
1022 }
1023
1024 PropertyDescriptor propertyDescriptor = null;
1025
1026 String[] intermediateProperties = collectionName.split("\\.");
1027 Class currentClass = boClass;
1028
1029 for (int i = 0; i < intermediateProperties.length; ++i) {
1030
1031 String currentPropertyName = intermediateProperties[i];
1032 propertyDescriptor = buildSimpleReadDescriptor(currentClass, currentPropertyName);
1033
1034 if (propertyDescriptor != null) {
1035
1036 Class type = propertyDescriptor.getPropertyType();
1037 if (Collection.class.isAssignableFrom(type)) {
1038 currentClass = getLegacyDataAdapter().determineCollectionObjectType(currentClass, currentPropertyName);
1039 } else {
1040 currentClass = propertyDescriptor.getPropertyType();
1041 }
1042 }
1043 }
1044
1045 return currentClass;
1046 }
1047
1048 static private Map<String, Map<String, PropertyDescriptor>> cache =
1049 new TreeMap<String, Map<String, PropertyDescriptor>>();
1050
1051
1052
1053
1054
1055
1056 public static PropertyDescriptor buildReadDescriptor(Class propertyClass, String propertyName) {
1057 if (propertyClass == null) {
1058 throw new IllegalArgumentException("invalid (null) propertyClass");
1059 }
1060 if (StringUtils.isBlank(propertyName)) {
1061 throw new IllegalArgumentException("invalid (blank) propertyName");
1062 }
1063
1064 PropertyDescriptor propertyDescriptor = null;
1065
1066 String[] intermediateProperties = propertyName.split("\\.");
1067 int lastLevel = intermediateProperties.length - 1;
1068 Class currentClass = propertyClass;
1069
1070 for (int i = 0; i <= lastLevel; ++i) {
1071
1072 String currentPropertyName = intermediateProperties[i];
1073 propertyDescriptor = buildSimpleReadDescriptor(currentClass, currentPropertyName);
1074
1075 if (i < lastLevel) {
1076
1077 if (propertyDescriptor != null) {
1078
1079 Class propertyType = propertyDescriptor.getPropertyType();
1080 if (getLegacyDataAdapter().isExtensionAttribute(currentClass, currentPropertyName, propertyType)) {
1081 propertyType = getLegacyDataAdapter().getExtensionAttributeClass(currentClass,
1082 currentPropertyName);
1083 }
1084 if (Collection.class.isAssignableFrom(propertyType)) {
1085 currentClass = getLegacyDataAdapter().determineCollectionObjectType(currentClass, currentPropertyName);
1086 } else {
1087 currentClass = propertyType;
1088 }
1089
1090 }
1091
1092 }
1093
1094 }
1095
1096 return propertyDescriptor;
1097 }
1098
1099
1100
1101
1102
1103
1104 public static PropertyDescriptor buildSimpleReadDescriptor(Class propertyClass, String propertyName) {
1105 if (propertyClass == null) {
1106 throw new IllegalArgumentException("invalid (null) propertyClass");
1107 }
1108 if (StringUtils.isBlank(propertyName)) {
1109 throw new IllegalArgumentException("invalid (blank) propertyName");
1110 }
1111
1112 PropertyDescriptor p = null;
1113
1114
1115 String propertyClassName = propertyClass.getName();
1116 Map<String, PropertyDescriptor> m = cache.get(propertyClassName);
1117 if (null != m) {
1118 p = m.get(propertyName);
1119 if (null != p) {
1120 return p;
1121 }
1122 }
1123
1124
1125
1126
1127
1128 PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(propertyClass);
1129 if (ArrayUtils.isNotEmpty(descriptors)) {
1130 for (PropertyDescriptor descriptor : descriptors) {
1131 if (descriptor.getName().equals(propertyName)) {
1132 p = descriptor;
1133 }
1134 }
1135 }
1136
1137
1138 if (p != null) {
1139 if (m == null) {
1140 m = new TreeMap<String, PropertyDescriptor>();
1141 cache.put(propertyClassName, m);
1142 }
1143 m.put(propertyName, p);
1144 }
1145
1146 return p;
1147 }
1148
1149 public Set<InactivationBlockingMetadata> getAllInactivationBlockingMetadatas(Class blockedClass) {
1150 return ddMapper.getAllInactivationBlockingMetadatas(ddIndex, blockedClass);
1151 }
1152
1153
1154
1155
1156
1157 public void performBeanOverrides() {
1158 timer.start("Processing BeanOverride beans");
1159 Collection<BeanOverride> beanOverrides = ddBeans.getBeansOfType(BeanOverride.class).values();
1160
1161 if (beanOverrides.isEmpty()) {
1162 LOG.info("DataDictionary.performOverrides(): No beans to override");
1163 }
1164 for (BeanOverride beanOverride : beanOverrides) {
1165
1166 Object bean = ddBeans.getBean(beanOverride.getBeanName());
1167 beanOverride.performOverride(bean);
1168 LOG.info("DataDictionary.performOverrides(): Performing override on bean: " + bean.toString());
1169 }
1170 timer.stop();
1171
1172 LOG.info( "\n" + timer.prettyPrint() );
1173 }
1174
1175 }