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