Java tutorial
/* * Copyright (c) 2010-2018 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.evolveum.midpoint.web.component.prism; import java.io.Serializable; import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Locale; import javax.xml.namespace.QName; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.jetbrains.annotations.Nullable; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismPropertyDefinition; import com.evolveum.midpoint.prism.PrismReferenceDefinition; import com.evolveum.midpoint.prism.PrismValue; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.delta.ReferenceDelta; import com.evolveum.midpoint.prism.path.IdItemPathSegment; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; /** * @author lazyman * @author katkav */ public class ContainerValueWrapper<C extends Containerable> extends PrismWrapper implements Serializable, DebugDumpable { private static final long serialVersionUID = 1L; private static final Trace LOGGER = TraceManager.getTrace(ContainerValueWrapper.class); private ContainerWrapper<C> containerWrapper; private PrismContainerValue<C> containerValue; private ValueStatus status; private ItemPath path; // WARNING!!! This field has to be called "properties" even if the right name should be "items". // But some Wicket reflection magic is looking for "properties" field. So, let it be properties for now. private List<ItemWrapper> properties; private boolean readonly; private boolean selected; private ContainerStatus objectStatus; ContainerValueWrapper(ContainerWrapper<C> containerWrapper, PrismContainerValue<C> containerValue, ContainerStatus objectStatus, ValueStatus status, ItemPath path) { Validate.notNull(status, "Container status must not be null."); Validate.notNull(containerValue.getParent().getDefinition(), "container definition must not be null."); Validate.notNull(status, "Container status must not be null."); this.containerWrapper = containerWrapper; this.containerValue = containerValue; this.objectStatus = objectStatus; this.status = status; this.path = path; } ContainerValueWrapper(PrismContainerValue<C> containerValue, ContainerStatus objectStatus, ValueStatus status, ItemPath path, boolean readOnly) { this(null, containerValue, objectStatus, status, path); this.readonly = readOnly; } public PrismContainerDefinition<C> getDefinition() { return containerValue.getParent().getDefinition(); } public void revive(PrismContext prismContext) throws SchemaException { if (containerValue != null) { containerValue.revive(prismContext); } if (getDefinition() != null) { getDefinition().revive(prismContext); } if (properties != null) { for (ItemWrapper itemWrapper : properties) { itemWrapper.revive(prismContext); } } } @Nullable ContainerWrapper<C> getContainer() { return containerWrapper; } public ValueStatus getStatus() { return status; } public void setStatus(ValueStatus status) { this.status = status; } public ItemPath getPath() { return path; } public PrismContainerValue<C> getContainerValue() { return containerValue; } public List<ItemWrapper> getItems() { if (properties == null) { properties = new ArrayList<>(); } return properties; } public void addEmptyProperties(List<ItemWrapper> emptyProperties) { emptyProperties.forEach(empty -> { if (!properties.contains(empty)) properties.add(empty); }); } public void setProperties(List<ItemWrapper> properties) { this.properties = properties; } public void computeStripes() { if (properties == null) { return; } int visibleProperties = 0; for (ItemWrapper item : properties) { if (item.isVisible()) { visibleProperties++; } if (visibleProperties % 2 == 0) { item.setStripe(true); } else { item.setStripe(false); } } } public boolean isMain() { return path == null || path.isEmpty(); } static String getDisplayNameFromItem(Item item) { Validate.notNull(item, "Item must not be null."); String displayName = item.getDisplayName(); if (StringUtils.isEmpty(displayName)) { QName name = item.getElementName(); if (name != null) { displayName = name.getLocalPart(); } else { displayName = item.getDefinition().getTypeName().getLocalPart(); } } return displayName; } public boolean hasChanged() { switch (getStatus()) { case DELETED: return true; case ADDED: case NOT_CHANGED: for (ItemWrapper item : getItems()) { if (item.hasChanged()) { return true; } } } return false; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("ContainerWrapper("); // builder.append(getDisplayNameFromItem(containerValue)); builder.append(" ("); builder.append(status); builder.append(") "); builder.append(getItems() == null ? null : getItems().size()); builder.append(" items)"); return builder.toString(); } /** * This methods check if we want to show property in form (e.g. * failedLogins, fetchResult, lastFailedLoginTimestamp must be invisible) * * @return * @deprecated will be implemented through annotations in schema */ @Deprecated private boolean skipProperty(PrismPropertyDefinition def) { final List<QName> names = new ArrayList<>(); names.add(PasswordType.F_FAILED_LOGINS); names.add(PasswordType.F_LAST_FAILED_LOGIN); names.add(PasswordType.F_LAST_SUCCESSFUL_LOGIN); names.add(PasswordType.F_PREVIOUS_SUCCESSFUL_LOGIN); names.add(ObjectType.F_FETCH_RESULT); // activation names.add(ActivationType.F_EFFECTIVE_STATUS); names.add(ActivationType.F_VALIDITY_STATUS); // user names.add(UserType.F_RESULT); // org and roles names.add(OrgType.F_APPROVAL_PROCESS); names.add(OrgType.F_APPROVER_EXPRESSION); names.add(OrgType.F_AUTOMATICALLY_APPROVED); names.add(OrgType.F_CONDITION); for (QName name : names) { if (name.equals(def.getName())) { return true; } } return false; } public boolean isReadonly() { // readonly flag in container is an override. Do not get the value from // definition // otherwise it will be propagated to items and overrides the item // definition. return readonly; } public void setReadonly(boolean readonly) { this.readonly = readonly; } public boolean isSelected() { return selected; } public void setSelected(boolean selected) { this.selected = selected; } public void sort() { Locale locale = WebModelServiceUtils.getLocale(); if (locale == null) { locale = Locale.getDefault(); } Collator collator = Collator.getInstance(locale); if (isSorted()) { collator.setStrength(Collator.SECONDARY); // e.g. "a" should be different from "" collator.setDecomposition(Collator.FULL_DECOMPOSITION); // slower but more precise Collections.sort(properties, new Comparator<ItemWrapper>() { @Override public int compare(ItemWrapper pw1, ItemWrapper pw2) { if (pw1 instanceof ContainerWrapper) { ((ContainerWrapper) pw1).sort(); } if (pw2 instanceof ContainerWrapper) { ((ContainerWrapper) pw2).sort(); } if (PropertyOrReferenceWrapper.class.isAssignableFrom(pw1.getClass()) && pw2 instanceof ContainerWrapper) { return -1; } if (PropertyOrReferenceWrapper.class.isAssignableFrom(pw2.getClass()) && pw1 instanceof ContainerWrapper) { return 1; } // return compareByDisplayNames(pw1, pw2, collator); } }); } else { Collections.sort(properties, new Comparator<ItemWrapper>() { @Override public int compare(ItemWrapper pw1, ItemWrapper pw2) { if (pw1 instanceof ContainerWrapper) { ((ContainerWrapper) pw1).sort(); } if (pw2 instanceof ContainerWrapper) { ((ContainerWrapper) pw2).sort(); } if (PropertyOrReferenceWrapper.class.isAssignableFrom(pw1.getClass()) && pw2 instanceof ContainerWrapper) { return -1; } if (PropertyOrReferenceWrapper.class.isAssignableFrom(pw2.getClass()) && pw1 instanceof ContainerWrapper) { return 1; } ItemDefinition id1 = pw1.getItemDefinition(); ItemDefinition id2 = pw2.getItemDefinition(); int displayOrder1 = (id1 == null || id1.getDisplayOrder() == null) ? Integer.MAX_VALUE : id1.getDisplayOrder(); int displayOrder2 = (id2 == null || id2.getDisplayOrder() == null) ? Integer.MAX_VALUE : id2.getDisplayOrder(); if (displayOrder1 == displayOrder2) { return compareByDisplayNames(pw1, pw2, collator); } else { return Integer.compare(displayOrder1, displayOrder2); } } }); } } private int compareByDisplayNames(ItemWrapper pw1, ItemWrapper pw2, Collator collator) { return collator.compare(pw1.getDisplayName(), pw2.getDisplayName()); } @Override public String debugDump(int indent) { StringBuilder sb = new StringBuilder(); DebugUtil.indentDebugDump(sb, indent); sb.append("ContainerValueWrapper: ");// .append(PrettyPrinter.prettyPrint(getName())); sb.append("\n"); DebugUtil.debugDumpWithLabelLn(sb, "displayName", getDisplayName(), indent + 1); DebugUtil.debugDumpWithLabel(sb, "status", status == null ? null : status.toString(), indent + 1); sb.append("\n"); DebugUtil.debugDumpWithLabelLn(sb, "main", isMain(), indent + 1); DebugUtil.debugDumpWithLabelLn(sb, "readonly", readonly, indent + 1); // DebugUtil.debugDumpWithLabel(sb, "showInheritedObjectAttributes", // showInheritedObjectAttributes, indent + 1); // sb.append("\n"); DebugUtil.debugDumpWithLabelLn(sb, "path", path == null ? null : path.toString(), indent + 1); DebugUtil.debugDumpWithLabelLn(sb, "containerDefinition", getDefinition() == null ? null : getDefinition().toString(), indent + 1); DebugUtil.debugDumpWithLabelLn(sb, "containerValue", containerValue == null ? null : containerValue.toString(), indent + 1); DebugUtil.debugDumpLabelLn(sb, "items", indent + 1); DebugUtil.debugDump(sb, properties, indent + 2, false); return sb.toString(); } public PrismContainerValue<C> createContainerValueAddDelta() throws SchemaException { if (!hasChanged()) { return null; } if (getStatus() != ValueStatus.ADDED) { return null; } PrismContainerValue<C> newValue = containerValue.clone(); for (ItemWrapper item : getItems()) { if (!item.hasChanged()) { continue; } if (item instanceof ContainerWrapper) { PrismContainer containerToAdd = ((ContainerWrapper) item).createContainerAddDelta(); newValue.addReplaceExisting(containerToAdd); } else { PropertyOrReferenceWrapper propOrRef = (PropertyOrReferenceWrapper) item; ItemPath path = propOrRef.getPath(); ItemDelta itemDelta = collectAddModifications(propOrRef); ItemPath itemPath = itemDelta.getParentPath().remainder(getContainer().getPath()); if (itemPath.first() instanceof IdItemPathSegment) { itemPath = itemPath.tail(); } itemDelta.setParentPath(itemPath); itemDelta.applyTo(newValue); } } return newValue; } public <C extends Containerable> ItemDelta collectAddModifications(PropertyOrReferenceWrapper itemWrapper) throws SchemaException { ItemPath containerPath = getPath() != null ? getPath() : ItemPath.EMPTY_PATH; if (itemWrapper instanceof PropertyWrapper) { ItemDelta pDelta = computePropertyDeltas((PropertyWrapper) itemWrapper, containerPath); if (!pDelta.isEmpty()) { // HACK to remove a password replace delta is to be created if (getContainer().getName().equals(CredentialsType.F_PASSWORD)) { if (pDelta.getValuesToDelete() != null) { pDelta.resetValuesToDelete(); pDelta.setValuesToReplace(new ArrayList()); } } } return pDelta; } if (itemWrapper instanceof ReferenceWrapper) { ReferenceDelta pDelta = computeReferenceDeltas((ReferenceWrapper) itemWrapper, containerPath); if (!pDelta.isEmpty()) { return pDelta; } } LOGGER.trace("Delta from wrapper: ignoring {}", itemWrapper); return null; } public <O extends ObjectType> void collectModifications(ObjectDelta<O> delta) throws SchemaException { if (!hasChanged()) { return; } for (ItemWrapper itemWrapper : getItems()) { if (!itemWrapper.hasChanged()) { continue; } ItemPath containerPath = getPath() != null ? getPath() : ItemPath.EMPTY_PATH; if (itemWrapper instanceof PropertyWrapper) { ItemDelta pDelta = computePropertyDeltas((PropertyWrapper) itemWrapper, containerPath); if (!pDelta.isEmpty()) { // HACK to remove a password replace delta is to be created if (getContainer().getName().equals(CredentialsType.F_PASSWORD)) { if (pDelta.getValuesToDelete() != null) { pDelta.resetValuesToDelete(); pDelta.setValuesToReplace(new ArrayList()); } } delta.addModification(pDelta); } } else if (itemWrapper instanceof ReferenceWrapper) { // if (containerPath.equals(ItemPath.EMPTY_PATH) && itemWrapper.getPath().getSegments().size() > 1){ // containerPath = itemWrapper.getPath().allExceptLast(); // } ReferenceDelta pDelta = computeReferenceDeltas((ReferenceWrapper) itemWrapper, containerPath); if (!pDelta.isEmpty()) { delta.addModification(pDelta); } } else if (itemWrapper instanceof ContainerWrapper) { ((ContainerWrapper) itemWrapper).collectModifications(delta); } else { LOGGER.trace("Delta from wrapper: ignoring {}", itemWrapper); } } } private ItemDelta computePropertyDeltas(PropertyWrapper propertyWrapper, ItemPath containerPath) { ItemDefinition itemDef = propertyWrapper.getItemDefinition(); ItemDelta pDelta = itemDef.createEmptyDelta(propertyWrapper.getPath()); addItemDelta(propertyWrapper, pDelta, itemDef, containerPath); return pDelta; } private ReferenceDelta computeReferenceDeltas(ReferenceWrapper referenceWrapper, ItemPath containerPath) { PrismReferenceDefinition propertyDef = referenceWrapper.getItemDefinition(); ReferenceDelta pDelta = new ReferenceDelta(referenceWrapper.getPath(), propertyDef, propertyDef.getPrismContext()); addItemDelta(referenceWrapper, pDelta, propertyDef, containerPath.subPath(propertyDef.getName())); return pDelta; } private void addItemDelta(PropertyOrReferenceWrapper itemWrapper, ItemDelta pDelta, ItemDefinition propertyDef, ItemPath containerPath) { for (Object vWrapper : itemWrapper.getValues()) { if (!(vWrapper instanceof ValueWrapper)) { continue; } ValueWrapper valueWrapper = (ValueWrapper) vWrapper; valueWrapper.normalize(propertyDef.getPrismContext()); ValueStatus valueStatus = valueWrapper.getStatus(); if (!valueWrapper.hasValueChanged() && (ValueStatus.NOT_CHANGED.equals(valueStatus) || ValueStatus.ADDED.equals(valueStatus))) { continue; } PrismValue newValCloned = ObjectWrapper.clone(valueWrapper.getValue()); PrismValue oldValCloned = ObjectWrapper.clone(valueWrapper.getOldValue()); switch (valueWrapper.getStatus()) { case ADDED: if (newValCloned != null) { if (SchemaConstants.PATH_PASSWORD.equivalent(containerPath)) { // password change will always look like add, // therefore we push replace if (LOGGER.isTraceEnabled()) { LOGGER.trace("Delta from wrapper: {} (password) ADD -> replace {}", pDelta.getPath(), newValCloned); } pDelta.setValuesToReplace(Arrays.asList(newValCloned)); } else if (propertyDef.isSingleValue()) { // values for single-valued properties // should be pushed via replace // in order to prevent problems e.g. with // summarizing deltas for // unreachable resources if (LOGGER.isTraceEnabled()) { LOGGER.trace("Delta from wrapper: {} (single,new) ADD -> replace {}", pDelta.getPath(), newValCloned); } pDelta.setValueToReplace(newValCloned); } else { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Delta from wrapper: {} (multi,new) ADD -> add {}", pDelta.getPath(), newValCloned); } pDelta.addValueToAdd(newValCloned); } } break; case DELETED: if (newValCloned != null) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Delta from wrapper: {} (new) DELETE -> delete {}", pDelta.getPath(), newValCloned); } pDelta.addValueToDelete(newValCloned); } if (oldValCloned != null) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Delta from wrapper: {} (old) DELETE -> delete {}", pDelta.getPath(), oldValCloned); } pDelta.addValueToDelete(oldValCloned); } break; case NOT_CHANGED: // this is modify... if (propertyDef.isSingleValue()) { // newValCloned.isEmpty() if (newValCloned != null && !newValCloned.isEmpty()) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Delta from wrapper: {} (single,new) NOT_CHANGED -> replace {}", pDelta.getPath(), newValCloned); } pDelta.setValuesToReplace(Arrays.asList(newValCloned)); } else { if (oldValCloned != null) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Delta from wrapper: {} (single,old) NOT_CHANGED -> delete {}", pDelta.getPath(), oldValCloned); } pDelta.addValueToDelete(oldValCloned); } } } else { if (newValCloned != null && !newValCloned.isEmpty()) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Delta from wrapper: {} (multi,new) NOT_CHANGED -> add {}", pDelta.getPath(), newValCloned); } pDelta.addValueToAdd(newValCloned); } if (oldValCloned != null) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Delta from wrapper: {} (multi,old) NOT_CHANGED -> delete {}", pDelta.getPath(), oldValCloned); } pDelta.addValueToDelete(oldValCloned); } } break; } } } private Item createItem(PropertyOrReferenceWrapper itemWrapper, ItemDefinition propertyDef) { List<PrismValue> prismValues = new ArrayList<>(); for (Object vWrapper : itemWrapper.getValues()) { if (!(vWrapper instanceof ValueWrapper)) { continue; } ValueWrapper valueWrapper = (ValueWrapper) vWrapper; valueWrapper.normalize(propertyDef.getPrismContext()); ValueStatus valueStatus = valueWrapper.getStatus(); if (!valueWrapper.hasValueChanged() && (ValueStatus.NOT_CHANGED.equals(valueStatus) || ValueStatus.ADDED.equals(valueStatus))) { continue; } prismValues.add(valueWrapper.getValue().clone()); } Item item = itemWrapper.getItem().clone(); try { item.addAll(prismValues); } catch (SchemaException e) { LoggingUtils.logException(LOGGER, "could not crate delta for " + itemWrapper.getItem(), e); return null; } return item; } public ContainerStatus getObjectStatus() { return objectStatus; } // TODO: unify with other isVisibleMethods public boolean isVisible() { PrismContainerDefinition<C> def = getDefinition(); if (def.isIgnored() || (def.isOperational() && !def.getTypeName().equals(MetadataType.COMPLEX_TYPE))) { return false; } if (def.isDeprecated() && containerValue.isEmpty()) { return false; } if (def.getTypeName().equals(MetadataType.COMPLEX_TYPE)) { return isShowMetadata(); } if (ValueStatus.DELETED.equals(status)) { return false; } // TODO: emphasized switch (objectStatus) { case MODIFYING: return canReadAndModify(def) || showEmptyCanReadAndModify(def); case ADDING: return emphasizedAndCanAdd(def) || showEmptyAndCanAdd(def); } return false; } private boolean canReadAndModify(PrismContainerDefinition<C> def) { return def.canRead(); // && def.canModify(); } private boolean showEmptyCanReadAndModify(PrismContainerDefinition<C> def) { return def.canRead() && isShowEmpty(); //def.canModify() && isShowEmpty(); } private boolean showEmptyAndCanAdd(PrismContainerDefinition<C> def) { return def.canAdd(); } private boolean emphasizedAndCanAdd(PrismContainerDefinition<C> def) { return def.canAdd() && def.isEmphasized(); } @Override public void setShowEmpty(boolean showEmpty, boolean recursive) { super.setShowEmpty(showEmpty, recursive); getItems().forEach(item -> { item.setShowEmpty(showEmpty, recursive); }); } @Override public void setShowMetadata(boolean showMetadata) { super.setShowMetadata(showMetadata); getItems().forEach(value -> { if (value instanceof ContainerWrapper) { ((ContainerWrapper<C>) value).setShowMetadata(showMetadata); } }); } // @Override public boolean checkRequired(PageBase pageBase) { boolean rv = true; for (ItemWrapper itemWrapper : getItems()) { if (!itemWrapper.checkRequired(pageBase)) { rv = false; // not returning directly as we want to go through all the values } } return rv; } public PropertyOrReferenceWrapper findPropertyWrapper(QName name) { Validate.notNull(name, "QName must not be null."); for (ItemWrapper wrapper : getItems()) { if (wrapper instanceof ContainerWrapper) { continue; } if (QNameUtil.match(name, wrapper.getItem().getElementName())) { return (PropertyOrReferenceWrapper) wrapper; } } return null; } public ItemWrapper findPropertyWrapper(ItemPath itemPath) { Validate.notNull(itemPath, "Item path must not be null."); for (ItemWrapper wrapper : getItems()) { if (wrapper instanceof ContainerWrapper) { continue; } if (itemPath.equivalent(wrapper.getPath())) { return (PropertyOrReferenceWrapper) wrapper; } } return null; } public <T extends Containerable> ContainerWrapper<T> findContainerWrapper(QName qname) { return findContainerWrapper(new ItemPath(qname)); } public <T extends Containerable> ContainerWrapper<T> findContainerWrapper(ItemPath path) { Validate.notNull(path, "QName must not be null."); for (ItemWrapper wrapper : getItems()) { if (!(wrapper instanceof ContainerWrapper)) { continue; } ContainerWrapper<T> containerWrapper = (ContainerWrapper<T>) wrapper; if (containerWrapper.getPath().equivalent(path)) { return containerWrapper; } else { ContainerWrapper<T> childrenContainer = containerWrapper.findContainerWrapper(path); if (childrenContainer != null) { return childrenContainer; } } } return null; } public ContainerValueWrapper<C> findContainerValueWrapper(ItemPath path) { Validate.notNull(path, "QName must not be null."); for (ItemWrapper wrapper : getItems()) { if (!(wrapper instanceof ContainerValueWrapper)) { continue; } return ((ContainerValueWrapper<C>) wrapper).findContainerValueWrapper(path); } return null; } public boolean containsMultivalueContainer() { for (ItemWrapper wrapper : getItems()) { if (!(wrapper instanceof ContainerWrapper)) { continue; } if (!((ContainerWrapper<C>) wrapper).getItemDefinition().isSingleValue()) { return true; } } return false; } public List<QName> getChildMultivalueContainersToBeAdded() { List<QName> pathList = new ArrayList<>(); for (ItemWrapper wrapper : getItems()) { if (!(wrapper instanceof ContainerWrapper)) { continue; } if (!((ContainerWrapper<C>) wrapper).getItemDefinition().canAdd() || !((ContainerWrapper<C>) wrapper).getItemDefinition().canModify()) { continue; } if (!((ContainerWrapper<C>) wrapper).getItemDefinition().isSingleValue()) { pathList.add(((ContainerWrapper<C>) wrapper).getName()); } } return pathList; } public String getDisplayName() { if (getContainer().isMain()) { return "prismContainer.mainPanelDisplayName"; } if (getDefinition() == null) { return WebComponentUtil.getDisplayName(containerValue); } if (getDefinition().isSingleValue()) { return ContainerWrapper.getDisplayNameFromItem(getContainerValue().getContainer()); } return WebComponentUtil.getDisplayName(containerValue); } }