1 /**
2 * Copyright 2005-2014 The Kuali Foundation
3 *
4 * Licensed under the Educational Community License, Version 2.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/ecl2.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.rice.krad.service;
17
18 import java.lang.reflect.InvocationTargetException;
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.Map;
22
23 import org.kuali.rice.core.api.uif.RemotableQuickFinder;
24 import org.kuali.rice.krad.bo.DataObjectRelationship;
25 import org.kuali.rice.krad.util.ForeignKeyFieldsPopulationState;
26
27 /**
28 * Adapter that supports "legacy" KNS/KRAD persistence, metadata, and object utility frameworks via runtime
29 * argument inspection
30 *
31 * @deprecated This class is deprecated by default, applications should *never*
32 * use this adapter directly
33 *
34 * @author Kuali Rice Team (rice.collab@kuali.org).
35 */
36 @Deprecated
37 public interface LegacyDataAppAdapter {
38
39 // BusinessObjectService
40
41 /**
42 * Saves the passed in object or list of objects via the persistence layer.
43 *
44 * @param dataObject the data object to save
45 */
46 <T> T save(T dataObject);
47
48 /**
49 * Links up any contained objects, and then saves the passed in object via the persistence layer.
50 *
51 * @param dataObject the data object to link and save
52 */
53 <T> T linkAndSave(T dataObject);
54
55 <T> T saveDocument(T document);
56
57 /**
58 * Retrieves an object instance identified by its primary key. For composite keys, use {@link #findByPrimaryKey(Class, Map)}
59 *
60 * @param clazz data object type class
61 * @param primaryKey the primary key object
62 * @return data object instance
63 */
64 <T> T findBySinglePrimaryKey(Class<T> clazz, Object primaryKey);
65
66 /**
67 * Retrieves an object instance identified by its primary keys and values. This can be done by constructing a map where the key
68 * to the map entry is the primary key attribute and the value of the entry being the primary key value. For composite keys,
69 * pass in each primaryKey attribute and its value as a map entry.
70 *
71 * @param clazz data object type class
72 * @param primaryKeys map of String->Object key values
73 * @return data object instance
74 */
75 <T> T findByPrimaryKey(Class<T> clazz, Map<String, ?> primaryKeys);
76
77 /**
78 * Deletes a data object from the database.
79 *
80 * @param dataObject the data object to delete
81 */
82 void delete(Object dataObject);
83
84 /**
85 * Deletes data objects from the database.
86 *
87 * @param clazz the entity type to delete
88 * @param fieldValues map String->Object of field values to match
89 */
90 public void deleteMatching(Class<?> clazz, Map<String, ?> fieldValues);
91 /**
92 * Retrieves an object instance identified by the class of the given object and the object's primary key values.
93 *
94 * @param dataObject the data object
95 * @return the retrieved data object or null if not found
96 */
97 <T> T retrieve(T dataObject);
98
99 /**
100 * This method retrieves a collection of data objects populated with data, such that each record in the database populates a
101 * new object instance.This will only retrieve business objects by class type.
102 *
103 * @param clazz the data object type class
104 * @return collection of all data objects of given type
105 */
106 <T> Collection<T> findAll(Class<T> clazz);
107
108 /**
109 * This method retrieves a collection of data objects populated with data, such that each record in the database populates a
110 * new object instance. This will retrieve data objects by class type and also by criteria passed in as key-value pairs,
111 * specifically attribute name and its expected value.
112 *
113 * @param clazz the data object type class
114 * @param fieldValues map String->Object of field values
115 * @return collection of matching data objects
116 */
117 <T> Collection<T> findMatching(Class<T> clazz, Map<String, ?> fieldValues);
118
119 /**
120 * This method retrieves a collection of business objects populated with data, such that each record in the database populates a
121 * new object instance. This will retrieve business objects by class type and also by criteria passed in as key-value pairs,
122 * specifically attribute name and its expected value. Performs an order by on sort field.
123 *
124 * @param clazz
125 * @param fieldValues
126 * @return collection of business objects
127 */
128 <T> Collection<T> findMatchingOrderBy(Class<T> clazz, Map<String, ?> fieldValues, String sortField, boolean sortAscending);
129 // PersistenceService
130
131 /**
132 * This method retrieves the primary key field values for the given data object
133 *
134 * @param dataObject data object whose primary key field name,value pairs you want
135 * @return a Map containing the names and values of primary key fields for the data object
136 * @throws IllegalArgumentException if the given Object is null
137 * @throws org.kuali.rice.krad.exception.ClassNotPersistableException if the given object is of a type not mapped in ORM
138 */
139 Map<String, ?> getPrimaryKeyFieldValues(Object dataObject);
140
141 /**
142 * @param persistableObject object whose objects need to be filled in based on primary keys
143 * @throws IllegalArgumentException if the given Object is null
144 * @throws org.kuali.rice.krad.exception.ClassNotPersistableException if the given object is of a type not described in the OJB repository
145 */
146 void retrieveNonKeyFields(Object persistableObject);
147
148 /**
149 * @param persistableObject object whose specified reference object needs to be filled in based on primary keys
150 * @param referenceObjectName the name of the reference object that will be filled in based on primary key values
151 * @throws IllegalArgumentException if the given Object is null
152 * @throws org.kuali.rice.krad.exception.ClassNotPersistableException if the given object is of a type not described in the OJB repository
153 */
154 void retrieveReferenceObject(Object persistableObject, String referenceObjectName);
155
156 /**
157 * This method refreshes all reference objects to this main object that are 'non-updateable'. In general, this means that if a
158 * reference object is configured to not be updated when the parent document is saved, then they are non-updated.
159 * This will not refresh updateable objects, which can cause problems when you're creating new objects.
160 * See PersistenceServiceImpl.isUpdateableReference() for the full logic.
161 * @param persistableObject - the businessObject to be refreshed
162 */
163 void refreshAllNonUpdatingReferences(Object persistableObject);
164
165 /**
166 * Returns the object underlying any ORM proxy layers
167 * @param o the object for which to determine the underlying non-ORM-proxy target
168 * @return the underlying non-ORM-proxy object
169 */
170 Object resolveProxy(Object o);
171
172 /**
173 * Returns whether the object is an ORM proxy
174 * @param object the candidate object
175 * @return true if the object is an ORM proxy
176 */
177 boolean isProxied(Object object);
178
179 // LookupService
180
181 /**
182 * Returns a collection of objects based on the given search parameters.
183 * Search results are bounded by the KNS search results limit determined for the class.
184 *
185 * @param clazz the data object type
186 * @param formProps field values for query
187 * @param unbounded whether the search results should be bounded
188 * @param allPrimaryKeyValuesPresentAndNotWildcard indicates whether or not the search only contains non-wildcarded primary key values
189 * @param searchResultsLimit if the search is bounded, the search results limit, otherwise ignored. null is equivalent to KNS default for the clazz
190 * @return collection of matching data objects
191 * @deprecated please use {@link #findCollectionBySearchHelper(Class, java.util.Map, java.util.List, boolean, boolean, Integer)} instead
192 */
193 @Deprecated
194 <T> Collection<T> findCollectionBySearchHelper(Class<T> clazz, Map<String, String> formProps, boolean unbounded,
195 boolean allPrimaryKeyValuesPresentAndNotWildcard, Integer searchResultsLimit);
196
197 /**
198 * Returns a collection of objects based on the given search parameters.
199 *
200 * <p>
201 * Search results are bounded by the KNS search results limit determined for the class.
202 * This implementation further isolates the UIFramework from the LookupService and should be used
203 * in place of the deprecated method.
204 * </p>
205 *
206 * @param clazz the data object type
207 * @param formProps field values for query
208 * @param wildcardAsLiteralPropertyNames list of fields for query that do not allow wildcards
209 * @param unbounded whether the search results should be bounded
210 * @param allPrimaryKeyValuesPresentAndNotWildcard indicates whether or not the search only contains non-wildcarded primary key values
211 * @param searchResultsLimit if the search is bounded, the search results limit, otherwise ignored. null is equivalent to KNS default for the clazz
212 * @return collection of matching data objects
213 */
214 <T> Collection<T> findCollectionBySearchHelper(Class<T> clazz, Map<String, String> formProps,
215 List<String> wildcardAsLiteralPropertyNames, boolean unbounded,
216 boolean allPrimaryKeyValuesPresentAndNotWildcard, Integer searchResultsLimit);
217
218 /**
219 * Retrieves a Object based on the search criteria, which should uniquely
220 * identify a record.
221 *
222 * @param clazz the data object type
223 * @param formProps field values for query
224 * @return first object in returned search results, or null if none found
225 */
226 <T> T findObjectBySearch(Class<T> clazz, Map<String, String> formProps);
227
228 boolean allPrimaryKeyValuesPresentAndNotWildcard(Class<?> boClass, Map<String, String> formProps);
229
230 // DAO interfaces are hoisted for krad or krad/kns shared services which still need to be preserved.
231 // they will internally call LegacyDataAdapter
232
233 // PersistenceStructureService
234
235 /**
236 * Returns a list of primary key field names for the given class.
237 */
238 List<String> listPrimaryKeyFieldNames(Class<?> clazz);
239
240 /**
241 * Determines the type of the collection object on the class with the collection with the given property name.
242 *
243 * @param containingClass the class of the object containing the collection
244 * @param collectionPropertyName the name of the property identifying the collection
245 *
246 * @return the Class of elements in the identified collection
247 *
248 * @throws IllegalArgumentException if the given class is not available in metadata or if the given collection property name is incorrect
249 */
250 Class<?> determineCollectionObjectType(Class<?> containingClass, String collectionPropertyName);
251
252 /**
253 *
254 * This method checks the foreign keys for a reference on a given BO, and tests that all fk fields are populated if any are
255 * populated.
256 *
257 * In other words, for a given reference, it finds all the attributes of the BO that make up the foreign keys, and checks to see
258 * if they all have values. It also keeps a list of all the fieldNames that do not have values.
259 *
260 * @param bo - A populated BusinessObject descendent. Must contain an attributed named referenceName.
261 * @param referenceName - The name of the field that is a reference we are analyzing.
262 * @return A populated ForeignKeyFieldsPopulation object which represents the state of population for the foreign key fields.
263 */
264 ForeignKeyFieldsPopulationState getForeignKeyFieldsPopulationState(Object bo, String referenceName);
265
266 /**
267 *
268 * This method will return a Map of all the foreign key fields and the corresponding primary key fields for a given reference.
269 *
270 * The Map structure is: Key(String fkFieldName) => Value(String pkFieldName)
271 *
272 * @param clazz - Class that contains the named reference
273 * @param attributeName - Name of the member that is the reference you want foreign keys for
274 * @return returns a Map populated as described above, with one entry per foreign key field
275 *
276 */
277 Map<String,String> getForeignKeysForReference(Class<?> clazz, String attributeName);
278
279 /**
280 * @param persistableObject
281 * @return true if all primary key fields of the string have a non-null (and non-empty, for Strings) value
282 * @throws IllegalArgumentException if the given Object is null
283 * @throws org.kuali.rice.krad.exception.ClassNotPersistableException if the given object is of a type not described in the OJB repository
284 */
285 boolean hasPrimaryKeyFieldValues(Object persistableObject);
286
287 /**
288 * Returns whether there is a reference defined in the persistence layer with the given name.
289 * Depending on the type of underlying persistence mechanism, this method may or may not return true
290 * when the referenceName really refers to a collection type.
291 *
292 * To determine whether a reference is a collection, use the hasCollection method instead.
293 *
294 * In OJB, this method will return false for collection references.
295 *
296 * @param boClass
297 * @param referenceName
298 * @return true if the reference exists
299 */
300 boolean hasReference(Class<?> boClass, String referenceName);
301
302 /**
303 * Returns whether BOs of the given class have a collection defined within them with the given collection name.
304 *
305 * @param boClass
306 * @param collectionName
307 * @return true if a collection is defined
308 */
309 boolean hasCollection(Class<?> boClass, String collectionName);
310
311 boolean isExtensionAttribute(Class<?> boClass, String attributePropertyName, Class<?> propertyType);
312
313 Class<?> getExtensionAttributeClass(Class<?> boClass, String attributePropertyName);
314
315 // DataObjectMetadataService
316
317 /**
318 * Determines the primary keys for the class of the given object, then for each
319 * key field retrieves the value from the object instance and populates the return
320 * map with the primary key name as the map key and the object value as the map value
321 *
322 * <p>Has DOMDS on the end because this is the version that delegates to DataObjectMetaDataService</p>
323 *
324 * @param dataObject - object whose primary key field name,value pairs you want
325 * @return a Map containing the names and values of fields for the given class which
326 * are designated as key fields in the OJB repository file or DataDictionary
327 * @throws IllegalArgumentException if the given Object is null
328 */
329 Map<String, ?> getPrimaryKeyFieldValuesDOMDS(Object dataObject);
330
331 /**
332 * Compares two dataObject instances for equality based on primary keys
333 *
334 * @param do1
335 * @param do2
336 * @return boolean indicating whether the two objects are equal.
337 */
338 boolean equalsByPrimaryKeys(Object do1, Object do2);
339
340 // ObjectUtils
341
342 // /**
343 // * Casts the given object to a PersistableBusinessObject, checking first whether or not it is a valid
344 // * PersistableBusinessObject.
345 // *
346 // * @param object the object to cast to a PersistableBusinessObject, must be non-null
347 // * @return the PersistableBusinessObject for the given object, will never return null
348 // * @throws IllegalArgumentException if the given object is null or does not represent a valid PersistableBusinessObject
349 // */
350 // PersistableBusinessObject toPersistableBusinessObject(Object object);
351
352 /**
353 * Materializes any references on the given object.
354 *
355 * @param object object to materialize
356 */
357 void materializeAllSubObjects(Object object);
358
359 /**
360 * Returns the type of the property with the given name on the supplied object. The property path may be nested.
361 *
362 * @param object the object against which to search
363 * @param propertyName the (optionally nested) property name for which to locate the type
364 * @return the type of the property
365 * @throws RuntimeException if a problem occurred (i.e. bad property name), this exception will be different
366 * depending on whether the underlying implementation is calling legacy code or not
367 */
368 Class<?> getPropertyType(Object object, String propertyName);
369
370 // PersistableBusinessObjectBase
371
372 /**
373 * Creates an instance of the extension for the given business object class.
374 */
375 Object getExtension(Class<?> businessObjectClass)
376 throws InstantiationException, IllegalAccessException;
377
378 /**
379 * Refreshes the specified reference object on the given business object.
380 */
381 void refreshReferenceObject(Object businessObject, String referenceObjectName);
382
383 // Misc...
384
385 /**
386 * Determines if the given ojbect is "lockable".
387 *
388 * @param object object for which to determine lockable
389 * @return true if lockable, false otherwise
390 */
391 boolean isLockable(Object object);
392
393 /**
394 * Verifies that the version number of the given data object (if it has one) matches what is currently in the
395 * database. If not, then the GlobalVariables message map will be updated with an error message and a
396 * ValidationException will be thrown.
397 *
398 * <p>If this particular data object does not have versioning, this method will do nothing.</p>
399 *
400 * @param dataObject the data object to check the version number for
401 *
402 * @throws org.kuali.rice.krad.exception.ValidationException if the version number doesn't match
403 */
404 void verifyVersionNumber(Object dataObject);
405
406 /**
407 * Returns the builder for a remotable quick finder for the given attribute name on the given containing class.
408 *
409 * @param containingClass the class on which to locate the attribute
410 * @param attributeName the name of the attribute for which to build the quickfinder on the specified containing class
411 * @return the remotable quickfinder, or null if no such finder could be created
412 */
413 RemotableQuickFinder.Builder createQuickFinder(Class<?> containingClass, String attributeName);
414
415 boolean isReferenceUpdatable(Class<?> boClass, String referenceName);
416
417 /**
418 *
419 * This method uses the persistence layer to determine the list of reference objects contained within this parent object. For
420 * example, an Account object contains sub-objects such as Chart, as well as the key that connects the two, String
421 * chartOfAccountsCode.
422 *
423 * The return structure is: Map<referenceName, referenceClass>.
424 *
425 * As an example, an Account object passed into this would return:
426 *
427 * 0:['chartOfAccounts', org.kuali.module.chart.bo.Chart] 1:['organization', org.kuali.module.chart.bo.Org] etc.
428 *
429 * @param boClass Class that would like to be analyzed for reference names
430 * @return Map containing the reference name for the key as a string, and the class of the reference as the value. If the object
431 * contains no references, then this Map will be empty.
432 *
433 */
434 Map<String, Class> listReferenceObjectFields(Class<?> boClass);
435
436 boolean isCollectionUpdatable(Class<?> boClass, String collectionName);
437
438 Map<String, Class> listCollectionObjectTypes(Class<?> boClass);
439
440 /**
441 *
442 * This method attempts to retrieve the reference from a BO if it exists.
443 *
444 * @param bo - populated BusinessObject instance that includes the referenceName property
445 * @param referenceName - name of the member/property to load
446 * @return A populated object from the DB, if it exists
447 *
448 */
449 Object getReferenceIfExists(Object bo, String referenceName);
450
451 /**
452 *
453 * This method examines whether all the foreign key fields for the specified reference contain values.
454 *
455 * @param bo
456 * @param referenceName
457 * @return true if they all are accessible and have values, false otherwise
458 *
459 */
460 boolean allForeignKeyValuesPopulatedForReference(Object bo, String referenceName);
461
462 /**
463 * This method gets the title attribute from the datadictionary for the given data object class
464 * @param dataObjectClass
465 * @return title if available, otherwise null
466 */
467 String getTitleAttribute(Class<?> dataObjectClass);
468
469 /**
470 *
471 * @param dataObjectClass
472 * @return true is supported, otherwise false
473 */
474 boolean areNotesSupported(Class<?> dataObjectClass);
475
476 /**
477 * Gets the identifier for a data object
478 * @param dataObject data object
479 * @return data object identifier
480 */
481 String getDataObjectIdentifierString(Object dataObject);
482
483 /**
484 * Get Inquiry class if not the title attribute
485 * @param dataObject
486 * @param propertyName
487 * @return class that represents the inquiry object class, null otherwise
488 */
489 Class<?> getInquiryObjectClassIfNotTitle(Object dataObject, String propertyName);
490
491 /**
492 * Get Inquiry parameters for given keys for data object/property name
493 * @param dataObject
494 * @param keys
495 * @param propertyName
496 * @return map of key value pairs, empty map otherwise
497 */
498 Map<String,String> getInquiryParameters(Object dataObject, List<String> keys, String propertyName);
499
500
501 /**
502 * Determines whether the given data object class has an associated lookup in the local
503 * running application
504 *
505 * @param dataObjectClass data object class to find lookup for
506 * @return boolean true if a lookup exists for the data object class, false if not
507 */
508 boolean hasLocalLookup(Class<?> dataObjectClass);
509
510 /**
511 * Determines whether the given data object class has an associated inquiry in the local
512 * running application
513 *
514 * @param dataObjectClass data object class to find inquiry for
515 * @return boolean true if a inquiry exists for the data object class, false if not
516 */
517 boolean hasLocalInquiry(Class<?> dataObjectClass);
518
519 /**
520 * Attempts to find a relationship for the given attribute within the given
521 * data object
522 *
523 * <p>
524 * First the data dictionary is queried to find any relationship definitions
525 * setup that include the attribute, if found the
526 * <code>BusinessObjectRetationship</code> is build from that. If not and
527 * the data object class is persistent, relationships are retrieved from the
528 * persistence service. Nested attributes are handled in addition to
529 * external business objects. If multiple relationships are found, the one
530 * that contains the least amount of joining keys is returned
531 * </p>
532 *
533 * @param dataObject - data object instance that contains the attribute
534 * @param dataObjectClass - class for the data object that contains the attribute
535 * @param attributeName - property name for the attribute
536 * @param attributePrefix - property prefix for the attribute
537 * @param keysOnly - indicates whether only primary key fields should be returned
538 * in the relationship
539 * @param supportsLookup - indicates whether the relationship should support lookup
540 * @param supportsInquiry - indicates whether the relationship should support inquiry
541 * @return BusinessObjectRelationship for the attribute, or null if not
542 * found
543 */
544 DataObjectRelationship getDataObjectRelationship(Object dataObject, Class<?> dataObjectClass,
545 String attributeName, String attributePrefix, boolean keysOnly, boolean supportsLookup,
546 boolean supportsInquiry);
547
548
549 /**
550 * Determines if a class is persistable
551 *
552 * @param dataObjectClass - data object instance that contains the attribute
553 * @return true if the given Class is persistable (is known to OJB or JPA)
554 */
555 boolean isPersistable(Class<?> dataObjectClass);
556
557 /**
558 * Recursive; sets all occurences of the property in the object, its nested objects and its object lists with the
559 * given value.
560 *
561 * @param bo
562 * @param propertyName
563 * @param type
564 * @param propertyValue
565 * @throws NoSuchMethodException
566 * @throws java.lang.reflect.InvocationTargetException
567 * @throws IllegalAccessException
568 */
569 void setObjectPropertyDeep(Object bo, String propertyName, Class<?> type,
570 Object propertyValue) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException;
571
572 /**
573 * Attempts to find the Class for the given potentially proxied object
574 *
575 * @param object the potentially proxied object to find the Class of
576 * @return the best Class which could be found for the given object
577 */
578 Class<?> materializeClassForProxiedObject(Object object);
579
580 /**
581 * This method safely extracts either simple values OR nested values. For example, if the bo is SubAccount, and the
582 * fieldName is
583 * a21SubAccount.subAccountTypeCode, this thing makes sure it gets the value off the very end attribute, no matter
584 * how deeply
585 * nested it is. The code would be slightly simpler if this was done recursively, but this is safer, and consumes a
586 * constant
587 * amount of memory, no matter how deeply nested it goes.
588 *
589 * @param bo
590 * @param fieldName
591 * @return The field value if it exists. If it doesnt, and the name is invalid, and
592 */
593 Object getNestedValue(Object bo, String fieldName);
594
595 /**
596 * This method safely creates a object from a class
597 * Convenience method to create new object and throw a runtime exception if it cannot
598 * If the class is an {@link org.kuali.rice.krad.bo.ExternalizableBusinessObject}, this method will determine the interface for the EBO and
599 * query the
600 * appropriate module service to create a new instance.
601 *
602 * @param clazz
603 * @return a newInstance() of clazz
604 */
605 Object createNewObjectFromClass(Class clazz);
606
607 /**
608 * This method is a OJB Proxy-safe way to test for null on a proxied object that may or may not be materialized yet.
609 * It is safe
610 * to use on a proxy (materialized or non-materialized) or on a non-proxy (ie, regular object). Note that this will
611 * force a
612 * materialization of the proxy if the object is a proxy and unmaterialized.
613 *
614 * @param object - any object, proxied or not, materialized or not
615 * @return true if the object (or underlying materialized object) is null, false otherwise
616 */
617 boolean isNull(Object object);
618
619 /**
620 * Sets the property of an object with the given value. Converts using the formatter of the given type if one is
621 * found.
622 *
623 * @param bo
624 * @param propertyName
625 * @param propertyType
626 * @param propertyValue
627 * @throws NoSuchMethodException
628 * @throws InvocationTargetException
629 * @throws IllegalAccessException
630 */
631 void setObjectProperty(Object bo, String propertyName, Class propertyType,
632 Object propertyValue) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException;
633
634 }