com.evolveum.midpoint.web.component.prism.ContainerWrapper.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.web.component.prism.ContainerWrapper.java

Source

/*
 * Copyright (c) 2010-2013 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.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;

import com.evolveum.midpoint.common.refinery.CompositeRefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.RefinedAssociationDefinition;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchema;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.schema.constants.SchemaConstants;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;

import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ResourceTypeUtil;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.PrettyPrinter;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
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.web.page.PageBase;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType;
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.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAssociationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationCapabilityType;

/**
 * @author lazyman
 */
public class ContainerWrapper<T extends PrismContainer> implements ItemWrapper, Serializable, DebugDumpable {

    private static final Trace LOGGER = TraceManager.getTrace(ContainerWrapper.class);

    private static final List<QName> INHERITED_OBJECT_ATTRIBUTES = Arrays.asList(ObjectType.F_NAME,
            ObjectType.F_DESCRIPTION, ObjectType.F_FETCH_RESULT, ObjectType.F_PARENT_ORG,
            ObjectType.F_PARENT_ORG_REF, ObjectType.F_TENANT_REF, FocusType.F_LINK, FocusType.F_LINK_REF);

    private static final String DOT_CLASS = ContainerWrapper.class.getName() + ".";
    private static final String CREATE_PROPERTIES = DOT_CLASS + "createProperties";

    private String displayName;
    private ObjectWrapper<? extends ObjectType> objectWrapper;
    private T container;
    private ContainerStatus status;

    private boolean main;
    private ItemPath path;
    private List<ItemWrapper> properties;

    private boolean readonly;
    private boolean showInheritedObjectAttributes;

    private OperationResult result;

    private PrismContainerDefinition containerDefinition;

    public ContainerWrapper(ObjectWrapper objectWrapper, T container, ContainerStatus status, ItemPath path,
            PageBase pageBase) {
        this(objectWrapper, container, status, path, true, pageBase);
    }

    private ContainerWrapper(ObjectWrapper objectWrapper, T container, ContainerStatus status, ItemPath path,
            boolean createProperties, PageBase pageBase) {
        Validate.notNull(container, "container must not be null.");
        Validate.notNull(status, "Container status must not be null.");
        Validate.notNull(pageBase, "pageBase must not be null.");

        this.objectWrapper = objectWrapper;
        this.container = container;
        this.status = status;
        this.path = path;
        main = path == null;
        readonly = objectWrapper.isReadonly(); // [pm] this is quite questionable
        showInheritedObjectAttributes = objectWrapper.isShowInheritedObjectAttributes();
        // have to be after setting "main" property
        containerDefinition = getItemDefinition();
        if (createProperties) {
            // HACK HACK HACK, the container wrapper should not parse itself. This code should not be here.
            // Constructor should NOT parse the object
            // the createProperties parameter is here to avoid looping when parsing associations
            properties = createProperties(pageBase);
        } else {
            properties = new ArrayList<>();
        }
    }

    public void revive(PrismContext prismContext) throws SchemaException {
        if (container != null) {
            container.revive(prismContext);
        }
        if (containerDefinition != null) {
            containerDefinition.revive(prismContext);
        }
        if (properties != null) {
            for (ItemWrapper itemWrapper : properties) {
                itemWrapper.revive(prismContext);
            }
        }
    }

    @Override
    public PrismContainerDefinition getItemDefinition() {
        if (main) {
            return objectWrapper.getDefinition();
        } else {
            return objectWrapper.getDefinition().findContainerDefinition(path);
        }
    }

    OperationResult getResult() {
        return result;
    }

    void clearResult() {
        result = null;
    }

    ObjectWrapper getObject() {
        return objectWrapper;
    }

    ContainerStatus getStatus() {
        return status;
    }

    public ItemPath getPath() {
        return path;
    }

    public T getItem() {
        return container;
    }

    public List<ItemWrapper> getItems() {
        return properties;
    }

    public ItemWrapper findPropertyWrapper(QName name) {
        Validate.notNull(name, "QName must not be null.");
        for (ItemWrapper wrapper : getItems()) {
            if (name.equals(wrapper.getItem().getElementName())) {
                return wrapper;
            }
        }
        return null;
    }

    private List<ItemWrapper> createProperties(PageBase pageBase) {
        result = new OperationResult(CREATE_PROPERTIES);

        List<ItemWrapper> properties = new ArrayList<ItemWrapper>();

        PrismContainerDefinition definition = null;
        PrismObject parent = getObject().getObject();
        Class clazz = parent.getCompileTimeClass();
        if (ShadowType.class.isAssignableFrom(clazz)) {
            QName name = containerDefinition.getName();

            if (ShadowType.F_ATTRIBUTES.equals(name)) {
                try {
                    definition = objectWrapper.getRefinedAttributeDefinition();

                    if (definition == null) {
                        PrismReference resourceRef = parent.findReference(ShadowType.F_RESOURCE_REF);
                        PrismObject<ResourceType> resource = resourceRef.getValue().getObject();

                        definition = pageBase.getModelInteractionService()
                                .getEditObjectClassDefinition((PrismObject<ShadowType>) objectWrapper.getObject(),
                                        resource, AuthorizationPhaseType.REQUEST)
                                .toResourceAttributeContainerDefinition();

                        if (LOGGER.isTraceEnabled()) {
                            LOGGER.trace("Refined account def:\n{}", definition.debugDump());
                        }
                    }
                } catch (Exception ex) {
                    LoggingUtils.logException(LOGGER, "Couldn't load definitions from refined schema for shadow",
                            ex);
                    result.recordFatalError(
                            "Couldn't load definitions from refined schema for shadow, reason: " + ex.getMessage(),
                            ex);

                    return properties;
                }
            } else {
                definition = containerDefinition;
            }
        } else if (ResourceType.class.isAssignableFrom(clazz)) {
            if (containerDefinition != null) {
                definition = containerDefinition;
            } else {
                definition = container.getDefinition();
            }
        } else {
            definition = containerDefinition;
        }

        if (definition == null) {
            LOGGER.error("Couldn't get property list from null definition {}",
                    new Object[] { container.getElementName() });
            return properties;
        }

        // assignments are treated in a special way -- we display names of
        // org.units and roles
        // (but only if ObjectWrapper.isShowAssignments() is true; otherwise
        // they are filtered out by ObjectWrapper)
        if (container.getCompileTimeClass() != null
                && AssignmentType.class.isAssignableFrom(container.getCompileTimeClass())) {

            for (Object o : container.getValues()) {
                PrismContainerValue<AssignmentType> pcv = (PrismContainerValue<AssignmentType>) o;

                AssignmentType assignmentType = pcv.asContainerable();

                if (assignmentType.getTargetRef() == null) {
                    continue;
                }

                // hack... we want to create a definition for Name
                // PrismPropertyDefinition def = ((PrismContainerValue)
                // pcv.getContainer().getParent()).getContainer().findProperty(ObjectType.F_NAME).getDefinition();
                PrismPropertyDefinition def = new PrismPropertyDefinition(ObjectType.F_NAME, DOMUtil.XSD_STRING,
                        pcv.getPrismContext());

                if (OrgType.COMPLEX_TYPE.equals(assignmentType.getTargetRef().getType())) {
                    def.setDisplayName("Org.Unit");
                    def.setDisplayOrder(100);
                } else if (RoleType.COMPLEX_TYPE.equals(assignmentType.getTargetRef().getType())) {
                    def.setDisplayName("Role");
                    def.setDisplayOrder(200);
                } else {
                    continue;
                }

                PrismProperty<Object> temp = def.instantiate();

                String value = formatAssignmentBrief(assignmentType);

                temp.setValue(new PrismPropertyValue<Object>(value));
                // TODO: do this.isReadOnly() - is that OK? (originally it was the default behavior for all cases)
                properties.add(new PropertyWrapper(this, temp, this.isReadonly(), ValueStatus.NOT_CHANGED));
            }

        } else if (isShadowAssociation()) {
            PrismContext prismContext = objectWrapper.getObject().getPrismContext();
            Map<QName, PrismContainer<ShadowAssociationType>> assocMap = new HashMap<>();
            if (objectWrapper.getAssociations() != null) {
                for (PrismContainerValue<ShadowAssociationType> cval : objectWrapper.getAssociations()) {
                    ShadowAssociationType associationType = cval.asContainerable();
                    QName assocName = associationType.getName();
                    PrismContainer<ShadowAssociationType> fractionalContainer = assocMap.get(assocName);
                    if (fractionalContainer == null) {
                        fractionalContainer = new PrismContainer<>(ShadowType.F_ASSOCIATION,
                                ShadowAssociationType.class, cval.getPrismContext());
                        fractionalContainer.setDefinition(cval.getParent().getDefinition());
                        // HACK: set the name of the association as the element name so wrapper.getName() will return correct data.
                        fractionalContainer.setElementName(assocName);
                        assocMap.put(assocName, fractionalContainer);
                    }
                    try {
                        fractionalContainer.add(cval.clone());
                    } catch (SchemaException e) {
                        // Should not happen
                        throw new SystemException("Unexpected error: " + e.getMessage(), e);
                    }
                }
            }

            PrismReference resourceRef = parent.findReference(ShadowType.F_RESOURCE_REF);
            PrismObject<ResourceType> resource = resourceRef.getValue().getObject();

            // HACK. The revive should not be here. Revive is no good. The next use of the resource will
            // cause parsing of resource schema. We need some centralized place to maintain live cached copies
            // of resources.
            try {
                resource.revive(prismContext);
            } catch (SchemaException e) {
                throw new SystemException(e.getMessage(), e);
            }
            RefinedResourceSchema refinedSchema;
            CompositeRefinedObjectClassDefinition rOcDef;
            try {
                refinedSchema = RefinedResourceSchema.getRefinedSchema(resource);
                rOcDef = refinedSchema.determineCompositeObjectClassDefinition(parent);
            } catch (SchemaException e) {
                throw new SystemException(e.getMessage(), e);
            }
            // Make sure even empty associations have their wrappers so they can be displayed and edited
            for (RefinedAssociationDefinition assocDef : rOcDef.getAssociations()) {
                QName name = assocDef.getName();
                if (!assocMap.containsKey(name)) {
                    PrismContainer<ShadowAssociationType> fractionalContainer = new PrismContainer<>(
                            ShadowType.F_ASSOCIATION, ShadowAssociationType.class, prismContext);
                    fractionalContainer.setDefinition(getItemDefinition());
                    // HACK: set the name of the association as the element name so wrapper.getName() will return correct data.
                    fractionalContainer.setElementName(name);
                    assocMap.put(name, fractionalContainer);
                }
            }

            for (Entry<QName, PrismContainer<ShadowAssociationType>> assocEntry : assocMap.entrySet()) {
                // HACK HACK HACK, the container wrapper should not parse itself. This code should not be here.
                AssociationWrapper assocWrapper = new AssociationWrapper(this, assocEntry.getValue(),
                        this.isReadonly(), ValueStatus.NOT_CHANGED);
                properties.add(assocWrapper);
            }

        } else { // if not an assignment

            if ((container.getValues().size() == 1 || container.getValues().isEmpty())
                    && (containerDefinition == null || containerDefinition.isSingleValue())) {

                // there's no point in showing properties for non-single-valued
                // parent containers,
                // so we continue only if the parent is single-valued

                Collection<ItemDefinition> propertyDefinitions = definition.getDefinitions();
                for (ItemDefinition itemDef : propertyDefinitions) {
                    if (itemDef instanceof PrismPropertyDefinition) {

                        PrismPropertyDefinition def = (PrismPropertyDefinition) itemDef;
                        if (def.isIgnored() || skipProperty(def)) {
                            continue;
                        }
                        if (!showInheritedObjectAttributes && INHERITED_OBJECT_ATTRIBUTES.contains(def.getName())) {
                            continue;
                        }

                        // capability handling for activation properties
                        if (isShadowActivation() && !hasCapability(def)) {
                            continue;
                        }

                        if (isShadowAssociation()) {
                            continue;
                        }

                        PrismProperty property = container.findProperty(def.getName());
                        boolean propertyIsReadOnly;
                        // decision is based on parent object status, not this
                        // container's one (because container can be added also
                        // to an existing object)
                        if (objectWrapper.getStatus() == ContainerStatus.MODIFYING) {

                            propertyIsReadOnly = !def.canModify();
                        } else {
                            propertyIsReadOnly = !def.canAdd();
                        }
                        if (property == null) {
                            properties.add(new PropertyWrapper(this, def.instantiate(), propertyIsReadOnly,
                                    ValueStatus.ADDED));
                        } else {
                            properties.add(new PropertyWrapper(this, property, propertyIsReadOnly,
                                    ValueStatus.NOT_CHANGED));
                        }
                    } else if (itemDef instanceof PrismReferenceDefinition) {
                        PrismReferenceDefinition def = (PrismReferenceDefinition) itemDef;

                        if (INHERITED_OBJECT_ATTRIBUTES.contains(def.getName())) {
                            continue;
                        }

                        PrismReference reference = container.findReference(def.getName());
                        boolean propertyIsReadOnly;
                        // decision is based on parent object status, not this
                        // container's one (because container can be added also
                        // to an existing object)
                        if (objectWrapper.getStatus() == ContainerStatus.MODIFYING) {

                            propertyIsReadOnly = !def.canModify();
                        } else {
                            propertyIsReadOnly = !def.canAdd();
                        }
                        if (reference == null) {
                            properties.add(new ReferenceWrapper(this, def.instantiate(), propertyIsReadOnly,
                                    ValueStatus.ADDED));
                        } else {
                            properties.add(new ReferenceWrapper(this, reference, propertyIsReadOnly,
                                    ValueStatus.NOT_CHANGED));
                        }

                    }
                }
            }
        }

        Collections.sort(properties, new ItemWrapperComparator());

        result.recomputeStatus();

        return properties;
    }

    private boolean isPassword(PrismPropertyDefinition def) {
        // in the future, this option could apply as well
        return CredentialsType.F_PASSWORD.equals(container.getElementName())
                || CredentialsType.F_PASSWORD.equals(def.getName());
    }

    private boolean isShadowAssociation() {
        if (!ShadowType.class.isAssignableFrom(getObject().getObject().getCompileTimeClass())) {
            return false;
        }

        if (!ShadowType.F_ASSOCIATION.equals(container.getElementName())) {
            return false;
        }

        return true;
    }

    private boolean isShadowActivation() {
        if (!ShadowType.class.isAssignableFrom(getObject().getObject().getCompileTimeClass())) {
            return false;
        }

        if (!ShadowType.F_ACTIVATION.equals(container.getElementName())) {
            return false;
        }

        return true;
    }

    private boolean hasCapability(PrismPropertyDefinition def) {
        ShadowType shadow = (ShadowType) getObject().getObject().asObjectable();

        ActivationCapabilityType cap = ResourceTypeUtil.getEffectiveCapability(shadow.getResource(),
                ActivationCapabilityType.class);

        if (ActivationType.F_VALID_FROM.equals(def.getName()) && cap.getValidFrom() == null) {
            return false;
        }

        if (ActivationType.F_VALID_TO.equals(def.getName()) && cap.getValidTo() == null) {
            return false;
        }

        if (ActivationType.F_ADMINISTRATIVE_STATUS.equals(def.getName()) && cap.getStatus() == null) {
            return false;
        }

        return true;
    }

    // FIXME temporary - brutal hack - the following three methods are copied from
    // AddRoleAssignmentAspect - Pavol M.

    private String formatAssignmentBrief(AssignmentType assignment) {
        StringBuilder sb = new StringBuilder();
        if (assignment.getTarget() != null) {
            sb.append(assignment.getTarget().getName());
        } else {
            sb.append(assignment.getTargetRef().getOid());
        }
        if (assignment.getActivation() != null && (assignment.getActivation().getValidFrom() != null
                || assignment.getActivation().getValidTo() != null)) {
            sb.append(" ");
            sb.append("(");
            sb.append(formatTimeIntervalBrief(assignment));
            sb.append(")");
        }
        if (assignment.getActivation() != null) {
            switch (assignment.getActivation().getAdministrativeStatus()) {
            case ARCHIVED:
                sb.append(", archived");
                break; // TODO i18n
            case ENABLED:
                sb.append(", enabled");
                break;
            case DISABLED:
                sb.append(", disabled");
                break;
            }
        }
        return sb.toString();
    }

    public static String formatTimeIntervalBrief(AssignmentType assignment) {
        StringBuilder sb = new StringBuilder();
        if (assignment != null && assignment.getActivation() != null
                && (assignment.getActivation().getValidFrom() != null
                        || assignment.getActivation().getValidTo() != null)) {
            if (assignment.getActivation().getValidFrom() != null
                    && assignment.getActivation().getValidTo() != null) {
                sb.append(formatTime(assignment.getActivation().getValidFrom()));
                sb.append("-");
                sb.append(formatTime(assignment.getActivation().getValidTo()));
            } else if (assignment.getActivation().getValidFrom() != null) {
                sb.append("from ");
                sb.append(formatTime(assignment.getActivation().getValidFrom()));
            } else {
                sb.append("to ");
                sb.append(formatTime(assignment.getActivation().getValidTo()));
            }
        }
        return sb.toString();
    }

    private static String formatTime(XMLGregorianCalendar time) {
        DateFormat formatter = DateFormat.getDateInstance();
        return formatter.format(time.toGregorianCalendar().getTime());
    }

    boolean isItemVisible(ItemWrapper item) {
        ItemDefinition def = item.getItemDefinition();
        if (def.isIgnored() || def.isOperational()) {
            return false;
        }

        if (def instanceof PrismPropertyDefinition && skipProperty((PrismPropertyDefinition) def)) {
            return false;
        }

        // we decide not according to status of this container, but according to
        // the status of the whole object
        if (objectWrapper.getStatus() == ContainerStatus.ADDING) {
            return def.canAdd();
        }

        // otherwise, object.getStatus() is MODIFYING

        if (def.canModify()) {
            return showEmpty(item);
        } else {
            if (def.canRead()) {
                return showEmpty(item);
            }
            return false;
        }
    }

    private boolean showEmpty(ItemWrapper item) {
        ObjectWrapper objectWrapper = getObject();
        List<ValueWrapper> valueWrappers = item.getValues();
        boolean isEmpty;
        if (valueWrappers == null) {
            isEmpty = true;
        } else {
            isEmpty = valueWrappers.isEmpty();
        }
        if (!isEmpty && valueWrappers.size() == 1) {
            ValueWrapper value = valueWrappers.get(0);
            if (ValueStatus.ADDED.equals(value.getStatus())) {
                isEmpty = true;
            }
        }
        return objectWrapper.isShowEmpty() || !isEmpty;
    }

    @Override
    public String getDisplayName() {
        if (StringUtils.isNotEmpty(displayName)) {
            return displayName;
        }
        return getDisplayNameFromItem(container);
    }

    @Override
    public void setDisplayName(String name) {
        this.displayName = name;
    }

    @Override
    public QName getName() {
        return getItem().getElementName();
    }

    public boolean isMain() {
        return main;
    }

    public void setMain(boolean main) {
        this.main = main;
    }

    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() {
        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(container));
        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<QName>();
        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() {
        PrismContainerDefinition def = getItemDefinition();
        if (def != null) {
            // todo take into account the containing object status (adding vs. modifying)
            return (def.canRead() && !def.canAdd() && !def.canModify());
        }
        return readonly;
    }

    public void setReadonly(boolean readonly) {
        this.readonly = readonly;
    }

    @Override
    public List<ValueWrapper> getValues() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isVisible() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isEmpty() {
        return getItem().isEmpty();
    }

    @Override
    public ContainerWrapper getContainer() {
        // TODO Auto-generated method stub
        return null;
    }

    //TODO add new PrismContainerValue to association container
    public void addValue() {
        getItems().add(createItem());
    }

    public ItemWrapper createItem() {
        ValueWrapper wrapper = new ValueWrapper(this, new PrismPropertyValue(null), ValueStatus.ADDED);
        return wrapper.getItem();
    }

    @Override
    public String debugDump() {
        return debugDump(0);
    }

    @Override
    public String debugDump(int indent) {
        StringBuilder sb = new StringBuilder();
        DebugUtil.indentDebugDump(sb, indent);
        sb.append("ContainerWrapper: ").append(PrettyPrinter.prettyPrint(getName())).append("\n");
        DebugUtil.debugDumpWithLabel(sb, "displayName", displayName, indent + 1);
        sb.append("\n");
        DebugUtil.debugDumpWithLabel(sb, "status", status == null ? null : status.toString(), indent + 1);
        sb.append("\n");
        DebugUtil.debugDumpWithLabel(sb, "main", main, indent + 1);
        sb.append("\n");
        DebugUtil.debugDumpWithLabel(sb, "readonly", readonly, indent + 1);
        sb.append("\n");
        DebugUtil.debugDumpWithLabel(sb, "showInheritedObjectAttributes", showInheritedObjectAttributes,
                indent + 1);
        sb.append("\n");
        DebugUtil.debugDumpWithLabel(sb, "path", path == null ? null : path.toString(), indent + 1);
        sb.append("\n");
        DebugUtil.debugDumpWithLabel(sb, "containerDefinition",
                containerDefinition == null ? null : containerDefinition.toString(), indent + 1);
        sb.append("\n");
        DebugUtil.debugDumpWithLabel(sb, "container", container == null ? null : container.toString(), indent + 1);
        sb.append("\n");
        DebugUtil.debugDumpLabel(sb, "properties", indent + 1);
        sb.append("\n");
        DebugUtil.debugDump(sb, properties, indent + 2, false);
        sb.append("\n");
        DebugUtil.debugDumpWithLabel(sb, "result", result, indent + 1);
        return sb.toString();
    }
}