1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.data.provider.annotation.impl;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.core.api.data.DataType;
20 import org.kuali.rice.krad.data.DataObjectService;
21 import org.kuali.rice.krad.data.KradDataServiceLocator;
22 import org.kuali.rice.krad.data.metadata.DataObjectAttribute;
23 import org.kuali.rice.krad.data.metadata.DataObjectAttributeRelationship;
24 import org.kuali.rice.krad.data.metadata.DataObjectCollection;
25 import org.kuali.rice.krad.data.metadata.DataObjectCollectionSortAttribute;
26 import org.kuali.rice.krad.data.metadata.DataObjectMetadata;
27 import org.kuali.rice.krad.data.metadata.DataObjectRelationship;
28 import org.kuali.rice.krad.data.metadata.MetadataConfigurationException;
29 import org.kuali.rice.krad.data.metadata.MetadataMergeAction;
30 import org.kuali.rice.krad.data.metadata.MetadataRepository;
31 import org.kuali.rice.krad.data.metadata.impl.DataObjectAttributeImpl;
32 import org.kuali.rice.krad.data.metadata.impl.DataObjectAttributeRelationshipImpl;
33 import org.kuali.rice.krad.data.metadata.impl.DataObjectCollectionImpl;
34 import org.kuali.rice.krad.data.metadata.impl.DataObjectCollectionSortAttributeImpl;
35 import org.kuali.rice.krad.data.metadata.impl.DataObjectMetadataImpl;
36 import org.kuali.rice.krad.data.metadata.impl.DataObjectRelationshipImpl;
37 import org.kuali.rice.krad.data.metadata.impl.MetadataCommonBase;
38 import org.kuali.rice.krad.data.provider.annotation.AttributeRelationship;
39 import org.kuali.rice.krad.data.provider.annotation.BusinessKey;
40 import org.kuali.rice.krad.data.provider.annotation.CollectionRelationship;
41 import org.kuali.rice.krad.data.provider.annotation.CollectionSortAttribute;
42 import org.kuali.rice.krad.data.provider.annotation.Description;
43 import org.kuali.rice.krad.data.provider.annotation.ForceUppercase;
44 import org.kuali.rice.krad.data.provider.annotation.InheritProperties;
45 import org.kuali.rice.krad.data.provider.annotation.InheritProperty;
46 import org.kuali.rice.krad.data.provider.annotation.KeyValuesFinderClass;
47 import org.kuali.rice.krad.data.provider.annotation.Label;
48 import org.kuali.rice.krad.data.provider.annotation.MergeAction;
49 import org.kuali.rice.krad.data.provider.annotation.NonPersistentProperty;
50 import org.kuali.rice.krad.data.provider.annotation.PropertyEditorClass;
51 import org.kuali.rice.krad.data.provider.annotation.ReadOnly;
52 import org.kuali.rice.krad.data.provider.annotation.Relationship;
53 import org.kuali.rice.krad.data.provider.annotation.Sensitive;
54 import org.kuali.rice.krad.data.provider.annotation.ShortLabel;
55 import org.kuali.rice.krad.data.provider.annotation.UifAutoCreateViews;
56 import org.kuali.rice.krad.data.provider.annotation.UifDisplayHint;
57 import org.kuali.rice.krad.data.provider.annotation.UifDisplayHints;
58 import org.kuali.rice.krad.data.provider.annotation.UifValidCharactersConstraintBeanName;
59 import org.kuali.rice.krad.data.provider.impl.MetadataProviderBase;
60
61 import javax.validation.constraints.NotNull;
62 import javax.validation.constraints.Size;
63 import java.lang.annotation.Annotation;
64 import java.lang.reflect.Field;
65 import java.lang.reflect.Method;
66 import java.lang.reflect.ParameterizedType;
67 import java.lang.reflect.Type;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.Collection;
71 import java.util.Collections;
72 import java.util.HashSet;
73 import java.util.List;
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public class AnnotationMetadataProviderImpl extends MetadataProviderBase {
90 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
91 .getLogger(AnnotationMetadataProviderImpl.class);
92
93 private boolean initializationAttempted = false;
94 private DataObjectService dataObjectService;
95
96
97
98
99 @Override
100 protected void initializeMetadata(Collection<Class<?>> types) {
101 if (initializationAttempted) {
102 return;
103 }
104 initializationAttempted = true;
105 if (LOG.isDebugEnabled()) {
106 LOG.debug("Processing annotations for the given list of data objects: " + types);
107 }
108 if (types == null || types.isEmpty()) {
109 LOG.warn(getClass().getSimpleName() + " was passed an empty list of types to initialize, doing nothing");
110 return;
111 }
112 LOG.info("Started Scanning For Metadata Annotations");
113 for (Class<?> type : types) {
114 if (LOG.isDebugEnabled()) {
115 LOG.debug("Processing Annotations on : " + type);
116 }
117 boolean annotationsFound = false;
118 DataObjectMetadataImpl metadata = new DataObjectMetadataImpl();
119 metadata.setProviderName(this.getClass().getSimpleName());
120 metadata.setType(type);
121
122 annotationsFound |= processClassLevelAnnotations(type, metadata);
123
124 annotationsFound |= processFieldLevelAnnotations(type, metadata);
125
126 annotationsFound |= processMethodLevelAnnotations(type, metadata);
127
128 annotationsFound |= processInheritedAttributes(type, metadata);
129 if (annotationsFound) {
130 masterMetadataMap.put(type, metadata);
131 }
132 }
133 LOG.info("Completed Scanning For Metadata Annotations");
134 if (LOG.isDebugEnabled()) {
135 LOG.debug("Annotation Metadata: " + masterMetadataMap);
136 }
137 }
138
139
140
141
142
143
144
145
146 protected boolean processClassLevelAnnotations(Class<?> clazz, DataObjectMetadataImpl metadata) {
147 boolean classAnnotationFound = false;
148 boolean fieldAnnotationsFound = false;
149
150 List<DataObjectAttribute> attributes = new ArrayList<DataObjectAttribute>(metadata.getAttributes());
151 Annotation[] classAnnotations = clazz.getAnnotations();
152 if (LOG.isDebugEnabled()) {
153 LOG.debug("Class-level annotations: " + Arrays.asList(classAnnotations));
154 }
155 for (Annotation a : classAnnotations) {
156
157
158 if (processAnnotationsforCommonMetadata(a, metadata)) {
159 classAnnotationFound = true;
160 continue;
161 }
162 if (a instanceof MergeAction) {
163 MetadataMergeAction mma = ((MergeAction) a).value();
164 if (!(mma == MetadataMergeAction.MERGE || mma == MetadataMergeAction.REMOVE)) {
165 throw new MetadataConfigurationException(
166 "Only the MERGE and REMOVE merge actions are supported since the annotation metadata provider can not specify all required properties and may only be used as an overlay.");
167 }
168 metadata.setMergeAction(mma);
169 classAnnotationFound = true;
170 continue;
171 }
172 if (a instanceof UifAutoCreateViews) {
173 metadata.setAutoCreateUifViewTypes(Arrays.asList(((UifAutoCreateViews) a).value()));
174 classAnnotationFound = true;
175 }
176 }
177 if (fieldAnnotationsFound) {
178 metadata.setAttributes(attributes);
179 }
180 return classAnnotationFound;
181 }
182
183
184
185
186
187
188
189
190 protected boolean processFieldLevelAnnotations(Class<?> clazz, DataObjectMetadataImpl metadata) {
191 boolean fieldAnnotationsFound = false;
192 boolean additionalClassAnnotationsFound = false;
193 List<DataObjectAttribute> attributes = new ArrayList<DataObjectAttribute>();
194 for (Field f : clazz.getDeclaredFields()) {
195 boolean fieldAnnotationFound = false;
196 String propertyName = f.getName();
197 DataObjectAttributeImpl attr = (DataObjectAttributeImpl) metadata.getAttribute(propertyName);
198 boolean existingAttribute = attr != null;
199 if (!existingAttribute) {
200 attr = new DataObjectAttributeImpl();
201 attr.setName(propertyName);
202 attr.setType(f.getType());
203 DataType dataType = DataType.getDataTypeFromClass(f.getType());
204 if (dataType == null) {
205 dataType = DataType.STRING;
206 }
207 attr.setDataType(dataType);
208 attr.setOwningType(metadata.getType());
209 }
210 Annotation[] fieldAnnotations = f.getDeclaredAnnotations();
211 if (LOG.isDebugEnabled()) {
212 LOG.debug(f.getDeclaringClass() + "." + f.getName() + " Field-level annotations: "
213 + Arrays.asList(fieldAnnotations));
214 }
215 for (Annotation a : fieldAnnotations) {
216
217 fieldAnnotationFound |= processAnnotationForAttribute(a, attr, metadata);
218 if (!fieldAnnotationFound) {
219 if (a instanceof BusinessKey) {
220 ArrayList<String> businessKeys = new ArrayList<String>(metadata.getBusinessKeyAttributeNames());
221 businessKeys.add(f.getName());
222 metadata.setBusinessKeyAttributeNames(businessKeys);
223
224
225 additionalClassAnnotationsFound = true;
226 continue;
227 }
228 if (a instanceof Relationship) {
229 addDataObjectRelationship(metadata, f, (Relationship) a);
230
231 additionalClassAnnotationsFound = true;
232 continue;
233 }
234 if (a instanceof CollectionRelationship) {
235 addDataObjectCollection(metadata, f, (CollectionRelationship) a);
236
237 additionalClassAnnotationsFound = true;
238 continue;
239 }
240 }
241 }
242 if (fieldAnnotationFound) {
243 attributes.add(attr);
244 fieldAnnotationsFound = true;
245 }
246 }
247 if (fieldAnnotationsFound) {
248 metadata.setAttributes(attributes);
249 }
250 return fieldAnnotationsFound || additionalClassAnnotationsFound;
251 }
252
253
254
255
256
257
258
259
260 protected boolean processAnnotationsforCommonMetadata(Annotation a, MetadataCommonBase metadata) {
261 if (a instanceof Label) {
262 if (StringUtils.isNotBlank(((Label) a).value())) {
263 metadata.setLabel(((Label) a).value());
264 return true;
265 }
266 }
267 if (a instanceof ShortLabel) {
268 metadata.setShortLabel(((ShortLabel) a).value());
269 return true;
270 }
271 if (a instanceof Description) {
272 metadata.setDescription(((Description) a).value());
273 return true;
274 }
275 return false;
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289 protected boolean processAnnotationForAttribute(Annotation a, DataObjectAttributeImpl attr,
290 DataObjectMetadataImpl metadata) {
291 if (a == null) {
292 return false;
293 }
294 if (a instanceof NonPersistentProperty) {
295 attr.setPersisted(false);
296 return true;
297 }
298 if (processAnnotationsforCommonMetadata(a, attr)) {
299 return true;
300 }
301 if (a instanceof ReadOnly) {
302 attr.setReadOnly(true);
303 return true;
304 }
305 if (a instanceof UifValidCharactersConstraintBeanName) {
306 attr.setValidCharactersConstraintBeanName(((UifValidCharactersConstraintBeanName) a).value());
307 return true;
308 }
309 if (a instanceof KeyValuesFinderClass) {
310 try {
311 attr.setValidValues(((KeyValuesFinderClass) a).value().newInstance());
312 return true;
313 } catch (Exception ex) {
314 LOG.error("Unable to instantiate options finder: " + ((KeyValuesFinderClass) a).value(), ex);
315 }
316 }
317 if (a instanceof NotNull) {
318 attr.setRequired(true);
319 return true;
320 }
321 if (a instanceof ForceUppercase) {
322 attr.setForceUppercase(true);
323 return true;
324 }
325 if (a instanceof PropertyEditorClass) {
326 try {
327 attr.setPropertyEditor(((PropertyEditorClass) a).value().newInstance());
328 return true;
329 } catch (Exception ex) {
330 LOG.warn("Unable to instantiate property editor class for " + metadata.getTypeClassName()
331 + "." + attr.getName() + " : " + ((PropertyEditorClass) a).value());
332 }
333 }
334 if (a instanceof Size) {
335
336
337 if (((Size) a).max() != Integer.MAX_VALUE) {
338 attr.setMaxLength((long) ((Size) a).max());
339 return true;
340 }
341 }
342 if (a instanceof Sensitive) {
343 attr.setSensitive(true);
344 return true;
345 }
346 if (a instanceof UifDisplayHints) {
347 attr.setDisplayHints(new HashSet<UifDisplayHint>(Arrays.asList(((UifDisplayHints) a).value())));
348 return true;
349 }
350 if (a instanceof MergeAction) {
351 MetadataMergeAction mma = ((MergeAction) a).value();
352 if (!(mma == MetadataMergeAction.MERGE || mma == MetadataMergeAction.REMOVE)) {
353 throw new MetadataConfigurationException(
354 "Only the MERGE and REMOVE merge actions are supported since the annotation metadata provider can not specify all required properties and may only be used as an overlay.");
355 }
356 attr.setMergeAction(mma);
357 return true;
358 }
359 return false;
360 }
361
362
363
364
365
366
367
368
369
370 protected String getPropertyNameFromGetterMethod(Method m) {
371 String propertyName = "";
372 if (m.getName().startsWith("get")) {
373 propertyName = StringUtils.uncapitalize(StringUtils.removeStart(m.getName(), "get"));
374 } else {
375 propertyName = StringUtils.uncapitalize(StringUtils.removeStart(m.getName(), "is"));
376 }
377 return propertyName;
378 }
379
380
381
382
383
384
385
386
387
388 protected boolean processMethodLevelAnnotations(Class<?> clazz, DataObjectMetadataImpl metadata) {
389 boolean fieldAnnotationsFound = false;
390 if (LOG.isDebugEnabled()) {
391 LOG.debug("Processing Method Annotations on " + clazz);
392 }
393 List<DataObjectAttribute> attributes = new ArrayList<DataObjectAttribute>(metadata.getAttributes());
394 for (Method m : clazz.getDeclaredMethods()) {
395
396
397
398 if (!m.isAnnotationPresent(NonPersistentProperty.class)) {
399 if (LOG.isTraceEnabled()) {
400 LOG.trace("Rejecting method " + m.getName()
401 + " because does not have NonPersistentProperty annotation");
402 }
403 continue;
404 }
405
406 if (!m.getName().startsWith("get") && !m.getName().startsWith("is")) {
407 if (LOG.isDebugEnabled()) {
408 LOG.debug("Rejecting method " + m.getName() + " because name does not match getter pattern");
409 }
410 continue;
411 }
412
413 if (m.getReturnType() == null || m.getParameterTypes().length > 0) {
414 if (LOG.isDebugEnabled()) {
415 LOG.debug("Rejecting method " + m.getName() + " because has no return type or has arguments");
416 }
417 continue;
418 }
419 String propertyName = getPropertyNameFromGetterMethod(m);
420 boolean fieldAnnotationFound = false;
421 boolean existingAttribute = true;
422 DataObjectAttributeImpl attr = (DataObjectAttributeImpl) metadata.getAttribute(propertyName);
423 if (attr == null) {
424 existingAttribute = false;
425 attr = new DataObjectAttributeImpl();
426 attr.setName(propertyName);
427 attr.setType(m.getReturnType());
428 DataType dataType = DataType.getDataTypeFromClass(m.getReturnType());
429 if (dataType == null) {
430 dataType = DataType.STRING;
431 }
432 attr.setDataType(dataType);
433 attr.setOwningType(metadata.getType());
434 }
435 Annotation[] methodAnnotations = m.getDeclaredAnnotations();
436 if (LOG.isDebugEnabled()) {
437 LOG.debug(m.getDeclaringClass() + "." + m.getName() + " Method-level annotations: "
438 + Arrays.asList(methodAnnotations));
439 }
440 for (Annotation a : methodAnnotations) {
441 fieldAnnotationFound |= processAnnotationForAttribute(a, attr, metadata);
442 }
443 if (fieldAnnotationFound) {
444 if (!existingAttribute) {
445 attributes.add(attr);
446 }
447 fieldAnnotationsFound = true;
448 }
449 }
450 if (fieldAnnotationsFound) {
451 metadata.setAttributes(attributes);
452 }
453
454 return fieldAnnotationsFound;
455 }
456
457
458
459
460
461
462
463
464 protected void addDataObjectRelationship(DataObjectMetadataImpl metadata, Field f, Relationship a) {
465 List<DataObjectRelationship> relationships = new ArrayList<DataObjectRelationship>(metadata.getRelationships());
466 DataObjectRelationshipImpl relationship = new DataObjectRelationshipImpl();
467 relationship.setName(f.getName());
468 Class<?> childType = f.getType();
469 relationship.setRelatedType(childType);
470 relationship.setReadOnly(true);
471 relationship.setSavedWithParent(false);
472 relationship.setDeletedWithParent(false);
473 relationship.setLoadedAtParentLoadTime(false);
474 relationship.setLoadedDynamicallyUponUse(true);
475
476 List<DataObjectAttributeRelationship> attributeRelationships = new ArrayList<DataObjectAttributeRelationship>();
477 List<String> referencePkFields = Collections.emptyList();
478 MetadataRepository metadataRepository = getDataObjectService().getMetadataRepository();
479 if (metadataRepository.contains(childType)) {
480 DataObjectMetadata childMetadata = metadataRepository.getMetadata(childType);
481 referencePkFields = childMetadata.getPrimaryKeyAttributeNames();
482 } else {
483
484 if (f.getType().getName().equals("org.kuali.rice.kim.api.identity.Person")) {
485 referencePkFields = Collections.singletonList("principalId");
486 }
487 }
488 int index = 0;
489 for (String pkField : a.foreignKeyFields()) {
490 attributeRelationships.add(new DataObjectAttributeRelationshipImpl(pkField, referencePkFields.get(index)));
491 index++;
492 }
493 relationship.setAttributeRelationships(attributeRelationships);
494
495 relationships.add(relationship);
496 metadata.setRelationships(relationships);
497 }
498
499
500
501
502
503
504
505
506 protected void addDataObjectCollection(DataObjectMetadataImpl metadata, Field f, CollectionRelationship a) {
507 List<DataObjectCollection> collections = new ArrayList<DataObjectCollection>(metadata.getCollections());
508 DataObjectCollectionImpl collection = new DataObjectCollectionImpl();
509 collection.setName(f.getName());
510
511 if ( !Collection.class.isAssignableFrom(f.getType()) ) {
512 throw new IllegalArgumentException(
513 "@CollectionRelationship annotations can only be on attributes of Collection type. Field: "
514 + f.getDeclaringClass().getName() + "." + f.getName() + " (" + f.getType() + ")");
515 }
516
517 if (a.collectionElementClass().equals(Object.class)) {
518 Type[] genericArgs = ((ParameterizedType) f.getGenericType()).getActualTypeArguments();
519 if (genericArgs.length == 0) {
520 throw new IllegalArgumentException(
521 "You can only leave off the collectionElementClass annotation on a @CollectionRelationship when the Collection type has been <typed>. Field: "
522 + f.getDeclaringClass().getName() + "." + f.getName() + " (" + f.getType() + ")");
523 }
524 collection.setRelatedType((Class<?>) genericArgs[0]);
525 } else {
526 collection.setRelatedType(a.collectionElementClass());
527 }
528
529 List<DataObjectAttributeRelationship> attributeRelationships = new ArrayList<DataObjectAttributeRelationship>(
530 a.attributeRelationships().length);
531 for (AttributeRelationship rel : a.attributeRelationships()) {
532 attributeRelationships.add(new DataObjectAttributeRelationshipImpl(rel.parentAttributeName(), rel
533 .childAttributeName()));
534 }
535 collection.setAttributeRelationships(attributeRelationships);
536
537 collection.setReadOnly(false);
538 collection.setSavedWithParent(false);
539 collection.setDeletedWithParent(false);
540 collection.setLoadedAtParentLoadTime(true);
541 collection.setLoadedDynamicallyUponUse(false);
542 List<DataObjectCollectionSortAttribute> sortAttributes = new ArrayList<DataObjectCollectionSortAttribute>(
543 a.sortAttributes().length);
544 for (CollectionSortAttribute csa : a.sortAttributes()) {
545 sortAttributes.add(new DataObjectCollectionSortAttributeImpl(csa.value(), csa.sortDirection()));
546 }
547 collection.setDefaultCollectionOrderingAttributeNames(sortAttributes);
548
549 collection.setIndirectCollection(a.indirectCollection());
550 collection.setMinItemsInCollection(a.minItemsInCollection());
551 collection.setMaxItemsInCollection(a.maxItemsInCollection());
552 if (StringUtils.isNotBlank(a.label())) {
553 collection.setLabel(a.label());
554 }
555 if (StringUtils.isNotBlank(a.elementLabel())) {
556 collection.setLabel(a.elementLabel());
557 }
558
559 collections.add(collection);
560 metadata.setCollections(collections);
561 }
562
563
564
565
566
567
568
569
570
571 protected boolean processInheritedAttributes(Class<?> clazz, DataObjectMetadataImpl metadata) {
572 if (LOG.isDebugEnabled()) {
573 LOG.debug("Processing InheritProperties field Annotations on " + clazz);
574 }
575 List<DataObjectAttribute> attributes = new ArrayList<DataObjectAttribute>(metadata.getAttributes());
576 boolean fieldAnnotationsFound = false;
577 for (Field f : clazz.getDeclaredFields()) {
578 boolean fieldAnnotationFound = false;
579 String propertyName = f.getName();
580
581 if (!f.isAnnotationPresent(InheritProperties.class) && !f.isAnnotationPresent(InheritProperty.class)) {
582 continue;
583 }
584 fieldAnnotationFound = true;
585
586 InheritProperty[] propertyList = null;
587 InheritProperties a = f.getAnnotation(InheritProperties.class);
588 if (a != null) {
589 propertyList = a.value();
590 } else {
591
592 InheritProperty ip = f.getAnnotation(InheritProperty.class);
593 propertyList = new InheritProperty[] { ip };
594 }
595 if (LOG.isDebugEnabled()) {
596 LOG.debug("InheritProperties found on " + clazz + "." + f.getName() + " : "
597 + Arrays.toString(propertyList));
598 }
599 for (InheritProperty inheritedProperty : propertyList) {
600 String inheritedPropertyName = inheritedProperty.name();
601 String extendedPropertyName = propertyName + "." + inheritedPropertyName;
602 DataObjectAttributeImpl attr = (DataObjectAttributeImpl) metadata.getAttribute(extendedPropertyName);
603 boolean existingAttribute = attr != null;
604 if (!existingAttribute) {
605
606
607
608
609 attr = new DataObjectAttributeImpl();
610 attr.setName(extendedPropertyName);
611 Class<?> relatedClass = f.getType();
612 try {
613 attr.setType(getTypeOfProperty(relatedClass, inheritedPropertyName));
614 DataType dataType = DataType.getDataTypeFromClass(attr.getType());
615 if (dataType == null) {
616 dataType = DataType.STRING;
617 }
618 attr.setDataType(dataType);
619 } catch (Exception e) {
620 throw new IllegalArgumentException("no field with name " + inheritedPropertyName
621 + " exists on " + relatedClass, e);
622 }
623
624
625 attr.setPersisted(false);
626 attr.setOwningType(metadata.getType());
627 attr.setInheritedFromType(relatedClass);
628 attr.setInheritedFromAttributeName(inheritedPropertyName);
629 attr.setInheritedFromParentAttributeName(propertyName);
630
631
632 processAnnotationForAttribute(inheritedProperty.label(), attr, metadata);
633
634 processAnnotationForAttribute(inheritedProperty.displayHints(), attr, metadata);
635
636 attributes.add(attr);
637 }
638 }
639
640 fieldAnnotationsFound |= fieldAnnotationFound;
641 }
642 if (fieldAnnotationsFound) {
643 metadata.setAttributes(attributes);
644 }
645 return fieldAnnotationsFound;
646 }
647
648
649
650
651
652
653
654
655
656
657
658 protected Class<?> getTypeOfProperty(Class<?> clazz, String propertyName) {
659 try {
660 Field f = clazz.getField(propertyName);
661 return f.getType();
662 } catch (Exception e) {
663
664 }
665 try {
666 Method m = clazz.getMethod("get" + StringUtils.capitalize(propertyName));
667 return m.getReturnType();
668 } catch (Exception e) {
669
670 }
671 try {
672 Method m = clazz.getMethod("is" + StringUtils.capitalize(propertyName));
673 return m.getReturnType();
674 } catch (Exception e) {
675
676 }
677 return null;
678 }
679
680
681
682
683
684
685
686 @Override
687 public boolean requiresListOfExistingTypes() {
688 return true;
689 }
690
691
692
693
694
695
696 public boolean isInitializationAttempted() {
697 return initializationAttempted;
698 }
699
700
701
702
703
704 public DataObjectService getDataObjectService() {
705 if (dataObjectService == null) {
706 dataObjectService = KradDataServiceLocator.getDataObjectService();
707 }
708 return dataObjectService;
709 }
710
711
712
713
714
715
716 public void setDataObjectService(DataObjectService dataObjectService) {
717 this.dataObjectService = dataObjectService;
718 }
719 }