1 /** 2 * Copyright 2005-2015 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 }