001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.data.metadata.impl; 017 018import java.lang.reflect.Field; 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.HashMap; 023import java.util.List; 024import java.util.Map; 025 026import org.apache.commons.lang.StringUtils; 027import org.kuali.rice.krad.data.metadata.DataObjectAttribute; 028import org.kuali.rice.krad.data.metadata.DataObjectAttributeRelationship; 029import org.kuali.rice.krad.data.metadata.DataObjectCollection; 030import org.kuali.rice.krad.data.metadata.DataObjectRelationship; 031import org.kuali.rice.krad.data.metadata.MetadataMergeAction; 032import org.kuali.rice.krad.data.provider.annotation.UifAutoCreateViewType; 033 034import com.google.common.annotations.Beta; 035 036/** 037 * Base implementation class for the metadata related to the data object as a whole. 038 * 039 * <p> 040 * Contains lists of all child elements. 041 * </p> 042 * 043 * @author Kuali Rice Team (rice.collab@kuali.org) 044 */ 045public class DataObjectMetadataImpl extends MetadataCommonBase implements DataObjectMetadataInternal { 046 private static final long serialVersionUID = 7722982931510558892L; 047 048 protected DataObjectMetadataInternal embedded; 049 /** 050 * Property used to help with debugging. 051 * 052 * It is used in the toString() method so you can determine from which provider this metadata was extracted. 053 */ 054 protected String providerName; 055 056 protected Class<?> type; 057 058 protected List<DataObjectAttribute> attributes; 059 protected Map<String, DataObjectAttribute> attributeMap; 060 protected List<String> removedAttributeNames; 061 protected List<String> orderedAttributeList = new ArrayList<String>(); 062 063 protected List<DataObjectCollection> collections; 064 protected Map<String, DataObjectCollection> collectionMap; 065 protected List<String> removedCollectionNames; 066 067 protected List<DataObjectRelationship> relationships; 068 protected Map<String, DataObjectRelationship> relationshipMap; 069 protected List<String> removedRelationshipNames; 070 071 protected Map<String, List<DataObjectRelationship>> attributeToRelationshipMap; 072 protected Map<String, DataObjectRelationship> lastAttributeToRelationshipMap; 073 074 protected List<String> primaryKeyAttributeNames; 075 protected List<String> businessKeyAttributeNames; 076 protected String primaryDisplayAttributeName; 077 protected boolean primaryDisplayAttributeSetManually; 078 079 protected Boolean supportsOptimisticLocking; 080 081 protected Collection<UifAutoCreateViewType> autoCreateUifViewTypes; 082 083 public DataObjectMetadataImpl() { 084 } 085 086 /** 087 * {@inheritDoc} 088 */ 089 @Override 090 public Object getUniqueKeyForMerging() { 091 return type; 092 } 093 094 /** 095 * {@inheritDoc} 096 */ 097 @Override 098 public Class<?> getType() { 099 return type; 100 } 101 102 /** 103 * Sets unknown class to determine type. 104 * 105 * @param type unknown class 106 */ 107 public void setType(Class<?> type) { 108 if (type == null) { 109 throw new IllegalArgumentException("The data object type may not be set to null."); 110 } 111 this.type = type; 112 } 113 114 /** 115 * Gets type based on unknown class. 116 * 117 * @return class type or null 118 */ 119 public String getTypeClassName() { 120 if (type == null) { 121 return null; 122 } 123 return type.getName(); 124 } 125 126 /** 127 * This is really a helper method for cases where these objects may need to be built up via Spring XML. 128 * 129 * @param typeClassName class type 130 */ 131 public void setTypeClassName(String typeClassName) { 132 try { 133 setType(Class.forName(typeClassName)); 134 } catch (ClassNotFoundException e) { 135 throw new IllegalArgumentException("ClassNotFoundException when setting data object type class name " 136 + typeClassName, e); 137 } 138 } 139 140 /** 141 * {@inheritDoc} 142 */ 143 @Override 144 public List<String> getPrimaryKeyAttributeNames() { 145 if (primaryKeyAttributeNames != null) { 146 return primaryKeyAttributeNames; 147 } 148 149 if (embedded != null) { 150 return embedded.getPrimaryKeyAttributeNames(); 151 } 152 153 return Collections.emptyList(); 154 } 155 156 /** 157 * Sets list of primary attribute names which make up key. 158 * 159 * @param primaryKeyAttributeNames list of attribute names. 160 */ 161 public void setPrimaryKeyAttributeNames(List<String> primaryKeyAttributeNames) { 162 if (primaryKeyAttributeNames == null) { 163 primaryKeyAttributeNames = Collections.emptyList(); 164 } 165 166 this.primaryKeyAttributeNames = Collections.unmodifiableList( primaryKeyAttributeNames ); 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 @Override 173 public List<String> getBusinessKeyAttributeNames() { 174 // If we have business keys, use that 175 if (businessKeyAttributeNames != null) { 176 return businessKeyAttributeNames; 177 } 178 179 // Otherwise, if we have an explicit PK, use that 180 if (primaryKeyAttributeNames != null) { 181 return primaryKeyAttributeNames; 182 } 183 184 // If neither has been set, go up the chain 185 if (embedded != null) { 186 return embedded.getBusinessKeyAttributeNames(); 187 } 188 189 return Collections.emptyList(); 190 } 191 192 /** 193 * Sets list of attribute names that make up business key. 194 * 195 * @param businessKeyAttributeNames attribute names 196 */ 197 public void setBusinessKeyAttributeNames(List<String> businessKeyAttributeNames) { 198 if (businessKeyAttributeNames == null) { 199 businessKeyAttributeNames = Collections.emptyList(); 200 } 201 202 this.businessKeyAttributeNames = Collections.unmodifiableList(businessKeyAttributeNames); 203 } 204 205 /** 206 * {@inheritDoc} 207 */ 208 @Override 209 public Boolean hasDistinctBusinessKey() { 210 return !getPrimaryKeyAttributeNames().equals(getBusinessKeyAttributeNames()); 211 } 212 213 /** 214 * {@inheritDoc} 215 */ 216 @Override 217 public String getPrimaryDisplayAttributeName() { 218 if (primaryDisplayAttributeName == null && !getBusinessKeyAttributeNames().isEmpty()) { 219 primaryDisplayAttributeName = getBusinessKeyAttributeNames().get(getBusinessKeyAttributeNames().size() - 1); 220 } 221 222 return primaryDisplayAttributeName; 223 // Notes for potential use cases if deemed necessary to implement. 224 // Since the last field of the PK does not generally change between 225 // metadata layers, these cases may not need to be considered. 226 // CASES: 227 // 1) primaryDisplayAttributeName != null ==> primaryDisplayAttributeName 228 // 2) primaryDisplayAttributeName == null && pk fields == null/empty && embedded != null ==> 229 // embedded.getprimaryDisplayAttributeName() 230 // 3) primaryDisplayAttributeName == null && pk fields == null/empty && embedded == null ==> null 231 // 4) primaryDisplayAttributeName == null && pk fields != null/empty && embedded == null ==> last field of PK 232 // 5) primaryDisplayAttributeName == null && pk fields != null/empty && embedded != null && embedded.primary 233 // display == null ==> last field of PK 234 // 6) primaryDisplayAttributeName == null && pk fields != null/empty && embedded != null && embedded.primary 235 // display != null ==> embedded.getprimaryDisplayAttributeName() 236 // If not set locally 237 // need to check embedded 238 // But - embedded could be dynamically or manually set as well 239 // how do we detect whether it's been set explicitly on the embedded? If we don't, then we always get the last 240 // attribute of the PK list on the embedding object 241 } 242 243 /** 244 * Sets list of attribute names used for display. 245 * 246 * @param primaryDisplayAttributeName list of attribute names. 247 */ 248 public void setPrimaryDisplayAttributeName(String primaryDisplayAttributeName) { 249 if (StringUtils.isBlank(primaryDisplayAttributeName)) { 250 this.primaryDisplayAttributeName = null; 251 this.primaryDisplayAttributeSetManually = false; 252 } else { 253 this.primaryDisplayAttributeName = primaryDisplayAttributeName; 254 this.primaryDisplayAttributeSetManually = true; 255 } 256 } 257 258 /** 259 * Orders attributes by defined order. 260 * 261 * <p> 262 * First looks to see if attributes are inherited, then looks at the declared fields based on the attribute 263 * type. 264 * </p> 265 * 266 * @param attributes list of data object attributes 267 * @return re-ordered list of data object attributes 268 */ 269 public List<DataObjectAttribute> orderAttributesByDefinedOrder(List<DataObjectAttribute> attributes) { 270 List<DataObjectAttribute> sorted = new ArrayList<DataObjectAttribute>(attributes.size()); 271 Map<String, DataObjectAttribute> keyedAttributes = new HashMap<String, DataObjectAttribute>(attributes.size()); 272 Map<String, List<DataObjectAttribute>> inheritedAttributes = new HashMap<String, List<DataObjectAttribute>>(); 273 274 for (DataObjectAttribute attr : attributes) { 275 if (attr.isInherited()) { 276 List<DataObjectAttribute> inheritedByProperty = inheritedAttributes.get(attr 277 .getInheritedFromParentAttributeName()); 278 279 if (inheritedByProperty == null) { 280 inheritedByProperty = new ArrayList<DataObjectAttribute>(); 281 inheritedAttributes.put(attr.getInheritedFromParentAttributeName(), inheritedByProperty); 282 } 283 284 inheritedByProperty.add(attr); 285 } else { 286 keyedAttributes.put(attr.getName(), attr); 287 } 288 } 289 290 for (Field f : getType().getDeclaredFields()) { 291 DataObjectAttribute attr = keyedAttributes.get(f.getName()); 292 293 if (attr != null) { 294 sorted.add(attr); 295 keyedAttributes.remove(f.getName()); 296 } 297 298 if (inheritedAttributes.containsKey(f.getName())) { 299 sorted.addAll(inheritedAttributes.get(f.getName())); 300 } 301 } 302 sorted.addAll(keyedAttributes.values()); 303 return sorted; 304 } 305 306 List<DataObjectAttribute> mergedAttributes = null; 307 308 /** 309 * {@inheritDoc} 310 */ 311 @Override 312 public List<DataObjectAttribute> getAttributes() { 313 // We have a local list and no overrides - return the existing list 314 if (attributes != null && embedded == null) { 315 return orderAttributesByDefinedOrder(attributes); 316 } 317 318 if (embedded != null) { 319 return orderAttributesByDefinedOrder(mergeLists(embedded.getAttributes(), attributes)); 320 } 321 322 return Collections.emptyList(); 323 } 324 325 /** 326 * Sets attributes. 327 * 328 * <p> 329 * Looks at merge actions when adding, so not all attributes are added. 330 * </p> 331 * 332 * @param attributes list of data object attributes 333 */ 334 public void setAttributes(List<DataObjectAttribute> attributes) { 335 if (attributes == null) { 336 attributes = Collections.emptyList(); 337 } 338 339 this.attributes = Collections.unmodifiableList(attributes); 340 mergedAttributes = null; 341 attributeMap = new HashMap<String, DataObjectAttribute>(attributes.size()); 342 removedAttributeNames = new ArrayList<String>(); 343 for (DataObjectAttribute attr : attributes) { 344 // TODO: This is not quite correct - we really only want to not add the NO_OVERRIDE items if they are 345 // overriding something. However, at the point this is running, we don't know whether we will be embedding 346 // anything... 347 if (attr.getMergeAction() != MetadataMergeAction.REMOVE 348 && attr.getMergeAction() != MetadataMergeAction.NO_OVERRIDE) { 349 attributeMap.put(attr.getName(), attr); 350 } 351 352 // since the attribute will still exist in the embedded metadata, we need to put a block in on the standard 353 // cascade 354 if (attr.getMergeAction() == MetadataMergeAction.REMOVE) { 355 removedAttributeNames.add(attr.getName()); 356 } 357 } 358 } 359 360 /** 361 * {@inheritDoc} 362 */ 363 @Override 364 public List<DataObjectCollection> getCollections() { 365 // We have a local list and no overrides - return the existing list 366 if (collections != null && embedded == null) { 367 return collections; 368 } 369 370 if (embedded != null) { 371 return mergeLists(embedded.getCollections(), collections); 372 } 373 374 return Collections.emptyList(); 375 } 376 377 /** 378 * Sets collections. 379 * 380 * <p> 381 * Looks at merge actions when adding, so not all collections are added. 382 * </p> 383 * 384 * @param collections list of data object collections or null 385 */ 386 public void setCollections(List<DataObjectCollection> collections) { 387 if (collections == null) { 388 this.collections = null; 389 return; 390 } 391 392 this.collections = Collections.unmodifiableList(collections); 393 collectionMap = new HashMap<String, DataObjectCollection>(collections.size()); 394 removedCollectionNames = new ArrayList<String>(); 395 for (DataObjectCollection coll : collections) { 396 // This is not quite correct - we really only want to not add the NO_OVERRIDE items if they are 397 // overriding something. However, at the point this is running, we don't know whether we will be embedding 398 // anything... 399 if (coll.getMergeAction() != MetadataMergeAction.REMOVE 400 && coll.getMergeAction() != MetadataMergeAction.NO_OVERRIDE) { 401 collectionMap.put(coll.getName(), coll); 402 } 403 404 // since the attribute will still exist in the embedded metadata, we need to put a block in on the standard 405 // cascade 406 if (coll.getMergeAction() == MetadataMergeAction.REMOVE) { 407 removedCollectionNames.add(coll.getName()); 408 } 409 } 410 } 411 412 /** 413 * {@inheritDoc} 414 */ 415 @Override 416 public List<DataObjectRelationship> getRelationships() { 417 // We have a local list and no overrides - return the existing list 418 if (relationships != null && embedded == null) { 419 return relationships; 420 } 421 422 if (embedded != null) { 423 return mergeLists(embedded.getRelationships(), relationships); 424 } 425 426 return Collections.emptyList(); 427 } 428 429 /** 430 * Sets relationships. 431 * 432 * <p> 433 * Looks at merge actions and whether the relationship is empty when adding, so not all relationships are added. 434 * </p> 435 * 436 * @param relationships list of data object relationships or null 437 */ 438 public void setRelationships(List<DataObjectRelationship> relationships) { 439 if (relationships == null) { 440 this.relationships = null; 441 relationshipMap = null; 442 lastAttributeToRelationshipMap = null; 443 attributeToRelationshipMap = null; 444 return; 445 } 446 447 this.relationships = Collections.unmodifiableList(relationships); 448 relationshipMap = new HashMap<String, DataObjectRelationship>(relationships.size()); 449 attributeToRelationshipMap = new HashMap<String, List<DataObjectRelationship>>(); 450 lastAttributeToRelationshipMap = new HashMap<String, DataObjectRelationship>(relationships.size()); 451 removedRelationshipNames = new ArrayList<String>(); 452 453 // Builds maps to link attribute names to their relationships 454 for (DataObjectRelationship rel : relationships) { 455 // This is not quite correct - we really only want to not add the NO_OVERRIDE items if they are 456 // overriding something. However, at the point this is running, we don't know whether we will be embedding 457 // anything... 458 if (rel.getMergeAction() != MetadataMergeAction.REMOVE 459 && rel.getMergeAction() != MetadataMergeAction.NO_OVERRIDE) { 460 // related object attribute name 461 relationshipMap.put(rel.getName(), rel); 462 463 // last attribute in list linking the objects 464 if (!rel.getAttributeRelationships().isEmpty()) { 465 DataObjectAttributeRelationship relAttr = rel.getAttributeRelationships().get( 466 rel.getAttributeRelationships().size() - 1); 467 lastAttributeToRelationshipMap.put(relAttr.getParentAttributeName(), rel); 468 } 469 470 // all relationships relating to an attribute 471 for (DataObjectAttributeRelationship relAttr : rel.getAttributeRelationships()) { 472 List<DataObjectRelationship> rels = attributeToRelationshipMap 473 .get(relAttr.getParentAttributeName()); 474 if (rels == null) { 475 rels = new ArrayList<DataObjectRelationship>(); 476 attributeToRelationshipMap.put(relAttr.getParentAttributeName(), rels); 477 } 478 rels.add(rel); 479 } 480 } 481 482 // since the attribute will still exist in the embedded metadata, we need to put a block in on the standard 483 // cascade 484 if (rel.getMergeAction() == MetadataMergeAction.REMOVE) { 485 removedRelationshipNames.add(rel.getName()); 486 } 487 } 488 relationshipMap = Collections.unmodifiableMap(relationshipMap); 489 lastAttributeToRelationshipMap = Collections.unmodifiableMap(lastAttributeToRelationshipMap); 490 attributeToRelationshipMap = Collections.unmodifiableMap(attributeToRelationshipMap); 491 } 492 493 /** 494 * {@inheritDoc} 495 */ 496 @Override 497 public DataObjectAttribute getAttribute(String attributeName) { 498 if (attributeName == null) { 499 return null; 500 } 501 502 DataObjectAttribute attribute = null; 503 504 // attempt to get it from the local attribute map (if any attributed defined locally) 505 if (attributes != null) { 506 attribute = attributeMap.get(attributeName); 507 } 508 509 // if we don't find one, but we have an embedded metadata object, check it 510 if (attribute == null && embedded != null) { 511 attribute = embedded.getAttribute(attributeName); 512 // but, ensure it's not on the removed attribute list 513 if (attribute != null && removedAttributeNames != null 514 && removedAttributeNames.contains(attribute.getName())) { 515 attribute = null; 516 } 517 } 518 519 return attribute; 520 } 521 522 /** 523 * {@inheritDoc} 524 */ 525 @Override 526 public DataObjectCollection getCollection(String collectionName) { 527 if (collectionName == null) { 528 return null; 529 } 530 531 DataObjectCollection collection = null; 532 533 // attempt to get it from the local attribute map (if any attributed defined locally) 534 if (collections != null) { 535 collection = collectionMap.get(collectionName); 536 } 537 538 // if we don't find one, but we have an embedded metadata object, check it 539 if (collection == null && embedded != null) { 540 collection = embedded.getCollection(collectionName); 541 // but, ensure it's not on the removed attribute list 542 if (collection != null && removedCollectionNames != null 543 && removedCollectionNames.contains(collection.getName())) { 544 collection = null; 545 } 546 } 547 548 return collection; 549 } 550 551 /** 552 * {@inheritDoc} 553 */ 554 @Override 555 public DataObjectRelationship getRelationship(String relationshipName) { 556 if (relationshipName == null) { 557 return null; 558 } 559 560 DataObjectRelationship relationship = null; 561 562 // attempt to get it from the local attribute map (if any attributed defined locally) 563 if (relationships != null) { 564 relationship = relationshipMap.get(relationshipName); 565 } 566 567 // if we don't find one, but we have an embedded metadata object, check it 568 if (relationship == null && embedded != null) { 569 relationship = embedded.getRelationship(relationshipName); 570 // but, ensure it's not on the removed attribute list 571 if (relationship != null && removedRelationshipNames != null 572 && removedRelationshipNames.contains(relationship.getName())) { 573 relationship = null; 574 } 575 } 576 577 return relationship; 578 } 579 580 /** 581 * {@inheritDoc} 582 */ 583 @Override 584 public List<DataObjectRelationship> getRelationshipsInvolvingAttribute(String attributeName) { 585 // somewhat complex, since it returns a list of all possible relationships 586 if (StringUtils.isBlank(attributeName)) { 587 return null; 588 } 589 590 Map<Object, DataObjectRelationship> relationships = new HashMap<Object, DataObjectRelationship>(); 591 // Look locally 592 if (attributeToRelationshipMap != null && attributeToRelationshipMap.containsKey(attributeName)) { 593 for (DataObjectRelationship rel : attributeToRelationshipMap.get(attributeName)) { 594 Object mergeKey = rel.getName(); 595 596 if (rel instanceof MetadataCommonInternal) { 597 mergeKey = ((MetadataCommonInternal) rel).getUniqueKeyForMerging(); 598 } 599 600 relationships.put(mergeKey, rel); 601 } 602 } 603 604 // now, if we have an embedded object, look for matching ones, but exclude if the relationship is the same 605 // as that means it was overridden by this bean 606 if (embedded != null) { 607 for (DataObjectRelationship rel : embedded.getRelationshipsInvolvingAttribute(attributeName)) { 608 Object mergeKey = rel.getName(); 609 610 if (rel instanceof MetadataCommonInternal) { 611 mergeKey = ((MetadataCommonInternal) rel).getUniqueKeyForMerging(); 612 } 613 614 if (!relationships.containsKey(mergeKey)) { 615 relationships.put(mergeKey, rel); 616 } 617 } 618 } 619 620 return new ArrayList<DataObjectRelationship>(relationships.values()); 621 } 622 623 /** 624 * {@inheritDoc} 625 */ 626 @Override 627 public DataObjectRelationship getRelationshipByLastAttributeInRelationship(String attributeName) { 628 // this returns a single record, so we can just use the first matching one we find 629 if (StringUtils.isBlank(attributeName)) { 630 return null; 631 } 632 633 DataObjectRelationship relationship = null; 634 635 // Look locally 636 if (lastAttributeToRelationshipMap != null) { 637 relationship = lastAttributeToRelationshipMap.get(attributeName); 638 } 639 640 // if nothing found local, recurse into the embedded provider 641 if (relationship == null && embedded != null) { 642 relationship = embedded.getRelationshipByLastAttributeInRelationship(attributeName); 643 } 644 645 return relationship; 646 } 647 648 /** 649 * {@inheritDoc} 650 */ 651 @Override 652 public DataObjectMetadataInternal getEmbedded() { 653 return embedded; 654 } 655 656 /** 657 * {@inheritDoc} 658 */ 659 @Override 660 public void setEmbedded(DataObjectMetadataInternal embedded) { 661 this.embedded = embedded; 662 setEmbeddedCommonMetadata(embedded); 663 } 664 665 /** 666 * Gets the metadata source. 667 * 668 * <p> 669 * Helper property to allow identification of the source of metadata. Value is transient, so it will not survive 670 * serialization. 671 * </p> 672 * 673 * @return metadata source 674 */ 675 public String getProviderName() { 676 return providerName; 677 } 678 679 /** 680 * Sets provider name. 681 * 682 * @param providerName name of provider 683 */ 684 public void setProviderName(String providerName) { 685 this.providerName = providerName; 686 } 687 688 /** 689 * {@inheritDoc} 690 */ 691 @Override 692 public String toString() { 693 StringBuilder builder = new StringBuilder(); 694 builder.append("DataObjectMetadata ["); 695 builder.append("type=").append(getType()).append(", "); 696 builder.append("typeLabel=").append(label).append(", "); 697 builder.append("backingObjectName=").append(backingObjectName); 698 if (attributes != null && !attributes.isEmpty()) { 699 builder.append(", ").append("attributes=").append(attributes); 700 } 701 if (primaryKeyAttributeNames != null && !primaryKeyAttributeNames.isEmpty()) { 702 builder.append(", ").append("primaryKeyAttributeNames=").append(primaryKeyAttributeNames); 703 } 704 if (getPrimaryDisplayAttributeName() != null) { 705 builder.append(", ").append("primaryDisplayAttributeName=").append(getPrimaryDisplayAttributeName()); 706 } 707 if (businessKeyAttributeNames != null && !businessKeyAttributeNames.isEmpty()) { 708 builder.append(", ").append("businessKeyAttributeNames=").append(businessKeyAttributeNames); 709 } 710 if (collections != null && !collections.isEmpty()) { 711 builder.append(", ").append("collections=").append(collections); 712 } 713 if (relationships != null && !relationships.isEmpty()) { 714 builder.append(", ").append("relationships=").append(relationships); 715 } 716 if (providerName != null) { 717 builder.append(", ").append("providerName=").append(providerName); 718 } 719 if (embedded != null) { 720 builder.append(", ").append("mergeAction=").append(mergeAction); 721 builder.append(", ").append("embedded=").append(embedded); 722 } 723 builder.append("]"); 724 return builder.toString(); 725 } 726 727 /** 728 * {@inheritDoc} 729 */ 730 @Override 731 public boolean isSupportsOptimisticLocking() { 732 if (supportsOptimisticLocking != null) { 733 return supportsOptimisticLocking; 734 } 735 736 if (embedded != null) { 737 return embedded.isSupportsOptimisticLocking(); 738 } 739 740 return false; 741 } 742 743 /** 744 * Sets whether optimistic locking is supported. 745 * 746 * @param supportsOptimisticLocking whether optimistic locking is supported 747 */ 748 public void setSupportsOptimisticLocking(boolean supportsOptimisticLocking) { 749 this.supportsOptimisticLocking = supportsOptimisticLocking; 750 } 751 752 /** 753 * {@inheritDoc} 754 */ 755 @Override 756 @Beta 757 public boolean shouldAutoCreateUifViewOfType(UifAutoCreateViewType viewType) { 758 if (getAutoCreateUifViewTypes() == null) { 759 return false; 760 } 761 762 return getAutoCreateUifViewTypes().contains(viewType) 763 || getAutoCreateUifViewTypes().contains(UifAutoCreateViewType.ALL); 764 } 765 766 /** 767 * {@inheritDoc} 768 */ 769 @Override 770 @Beta 771 public Collection<UifAutoCreateViewType> getAutoCreateUifViewTypes() { 772 if (autoCreateUifViewTypes != null) { 773 return autoCreateUifViewTypes; 774 } 775 776 if (embedded != null) { 777 return embedded.getAutoCreateUifViewTypes(); 778 } 779 780 return null; 781 } 782 783 /** 784 * BETA: Sets list of UIF view types that will be auto created. 785 * 786 * @param autoCreateUifViewTypes UIF view types 787 */ 788 @Beta 789 public void setAutoCreateUifViewTypes(Collection<UifAutoCreateViewType> autoCreateUifViewTypes) { 790 this.autoCreateUifViewTypes = autoCreateUifViewTypes; 791 } 792 793 /** 794 * Gets sorted attribute list. 795 * 796 * @return ordered attribute list 797 */ 798 public List<String> getOrderedAttributeList() { 799 return orderedAttributeList; 800 } 801 802 /** 803 * Sets sorted attribute list. 804 * 805 * @param orderedAttributeList sorted attributes 806 */ 807 public void setOrderedAttributeList(List<String> orderedAttributeList) { 808 this.orderedAttributeList = orderedAttributeList; 809 } 810 811}