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

Java tutorial

Introduction

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

Source

/*
 * Copyright (c) 2010-2017 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.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.xml.namespace.QName;

import org.apache.commons.lang.Validate;

import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.gui.api.util.ModelServiceLocator;
import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils;
import com.evolveum.midpoint.model.api.ModelInteractionService;
import com.evolveum.midpoint.prism.Containerable;
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismObjectDefinition;
import com.evolveum.midpoint.prism.PrismReference;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.ItemPathSegment;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.ExpressionEvaluationException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SecurityViolationException;
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.xml.ns._public.common.common_3.ApprovalSchemaType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.NonceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationExecutionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordHistoryEntryType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SecurityQuestionsCredentialsType;
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.SubjectedObjectSelectorType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.TriggerType;

/**
 * @author Viliam Repan (lazyman)
 */
public class ObjectWrapperFactory {

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

    private static final String DOT_CLASS = ObjectWrapperFactory.class.getName() + ".";
    private static final String CREATE_CONTAINERS = DOT_CLASS + "createContainers";
    private static final String CREATE_OBJECT_WRAPPER = DOT_CLASS + "createObjectWrapper";

    private static final List<QName> CONTAINERS_TO_IGNORE = Arrays.asList(SubjectedObjectSelectorType.COMPLEX_TYPE,
            TriggerType.COMPLEX_TYPE, OperationExecutionType.COMPLEX_TYPE, ApprovalSchemaType.COMPLEX_TYPE,
            PasswordHistoryEntryType.COMPLEX_TYPE, SecurityQuestionsCredentialsType.COMPLEX_TYPE,
            NonceType.COMPLEX_TYPE);

    private ModelServiceLocator modelServiceLocator;

    private OperationResult result;

    public ObjectWrapperFactory(ModelServiceLocator modelServiceLocator) {
        Validate.notNull(modelServiceLocator, "Service locator must not be null");

        this.modelServiceLocator = modelServiceLocator;
    }

    public OperationResult getResult() {
        return result;
    }

    public <O extends ObjectType> ObjectWrapper<O> createObjectWrapper(String displayName, String description,
            PrismObject<O> object, ContainerStatus status, Task task) {
        return createObjectWrapper(displayName, description, object, status, AuthorizationPhaseType.REQUEST, task);
    }

    public <O extends ObjectType> ObjectWrapper<O> createObjectWrapper(String displayName, String description,
            PrismObject<O> object, ContainerStatus status, AuthorizationPhaseType authorizationPhase, Task task) {
        if (authorizationPhase == null) {
            authorizationPhase = AuthorizationPhaseType.REQUEST;
        }
        try {
            OperationResult result = task.getResult();

            PrismObjectDefinition<O> objectDefinitionForEditing = modelServiceLocator.getModelInteractionService()
                    .getEditObjectDefinition(object, authorizationPhase, task, result);
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Edit definition for {}:\n{}", object, objectDefinitionForEditing.debugDump(1));
            }

            if (objectDefinitionForEditing != null) {
                object.setDefinition(objectDefinitionForEditing);
            }

            RefinedObjectClassDefinition objectClassDefinitionForEditing = null;
            if (isShadow(object)) {
                PrismReference resourceRef = object.findReference(ShadowType.F_RESOURCE_REF);
                PrismObject<ResourceType> resource = resourceRef.getValue().getObject();
                Validate.notNull(resource, "No resource object in the resourceRef");
                objectClassDefinitionForEditing = modelServiceLocator.getModelInteractionService()
                        .getEditObjectClassDefinition((PrismObject<ShadowType>) object, resource,
                                authorizationPhase, task, result);
                if (objectClassDefinitionForEditing != null) {
                    object.findOrCreateContainer(ShadowType.F_ATTRIBUTES)
                            .applyDefinition((PrismContainerDefinition) objectClassDefinitionForEditing
                                    .toResourceAttributeContainerDefinition());
                    ;
                }

            }
            return createObjectWrapper(displayName, description, object, objectDefinitionForEditing,
                    objectClassDefinitionForEditing, status, task, result);
        } catch (SchemaException | ConfigurationException | ObjectNotFoundException | ExpressionEvaluationException
                | CommunicationException | SecurityViolationException ex) {
            throw new SystemException(ex);
        }
    }

    public <O extends ObjectType> ObjectWrapper<O> createObjectWrapper(String displayName, String description,
            PrismObject<O> object, PrismObjectDefinition<O> objectDefinitionForEditing,
            RefinedObjectClassDefinition objectClassDefinitionForEditing, ContainerStatus status, Task task)
            throws SchemaException {
        return createObjectWrapper(displayName, description, object, objectDefinitionForEditing,
                objectClassDefinitionForEditing, status, task, null);
    }

    private <O extends ObjectType> ObjectWrapper<O> createObjectWrapper(String displayName, String description,
            PrismObject<O> object, PrismObjectDefinition<O> objectDefinitionForEditing,
            RefinedObjectClassDefinition objectClassDefinitionForEditing, ContainerStatus status, Task task,
            OperationResult result) throws SchemaException {

        if (result == null) {
            this.result = new OperationResult(CREATE_OBJECT_WRAPPER);
        } else {
            this.result = result;
        }

        ObjectWrapper<O> objectWrapper = new ObjectWrapper<>(displayName, description, object, status);

        List<ContainerWrapper<? extends Containerable>> containerWrappers = createContainerWrappers(objectWrapper,
                object, objectDefinitionForEditing, status, task, this.result);
        objectWrapper.setContainers(containerWrappers);

        this.result.computeStatusIfUnknown();

        objectWrapper.setResult(this.result);

        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Created object wrapper:\n{}", objectWrapper.debugDump());
        }

        return objectWrapper;
    }

    private <O extends ObjectType> List<ContainerWrapper<? extends Containerable>> createContainerWrappers(
            ObjectWrapper<O> oWrapper, PrismObject<O> object, PrismObjectDefinition<O> objectDefinitionForEditing,
            ContainerStatus cStatus, Task task, OperationResult pResult) throws SchemaException {
        OperationResult result = pResult.createSubresult(CREATE_CONTAINERS);

        List<ContainerWrapper<? extends Containerable>> containerWrappers = new ArrayList<>();

        ContainerWrapperFactory cwf = new ContainerWrapperFactory(modelServiceLocator);
        try {
            ContainerWrapper<O> mainContainerWrapper = cwf.createContainerWrapper(object, oWrapper.getStatus(),
                    cStatus, ItemPath.EMPTY_PATH, task);
            mainContainerWrapper.setDisplayName("prismContainer.mainPanelDisplayName");
            result.addSubresult(cwf.getResult());
            containerWrappers.add(mainContainerWrapper);

            addContainerWrappers(containerWrappers, oWrapper, object, null, task, result);
        } catch (SchemaException | RuntimeException e) {
            LoggingUtils.logUnexpectedException(LOGGER, "Error occurred during container wrapping" + e.getMessage(),
                    e);
            result.recordFatalError("Error occurred during container wrapping, reason: " + e.getMessage(), e);
            throw e;
        }

        containerWrappers.sort(new ItemWrapperComparator());
        result.recomputeStatus();
        result.recordSuccessIfUnknown();

        return containerWrappers;
    }

    private <O extends ObjectType, C extends Containerable> void addContainerWrappers(
            List<ContainerWrapper<? extends Containerable>> containerWrappers, ObjectWrapper<O> oWrapper,
            PrismContainer<C> parentContainer, ItemPath path, Task task, OperationResult result)
            throws SchemaException {

        PrismContainerDefinition<C> parentContainerDefinition = parentContainer.getDefinition();

        List<ItemPathSegment> segments = new ArrayList<>();
        if (path != null) {
            segments.addAll(path.getSegments());
        }
        ItemPath parentPath = new ItemPath(segments);
        for (ItemDefinition def : (Collection<ItemDefinition>) parentContainerDefinition.getDefinitions()) {
            if (!(def instanceof PrismContainerDefinition)) {
                continue;
            }
            if (isIgnoreContainer(def.getTypeName())) {
                continue;
            }

            if (def.isExperimental()
                    && !WebModelServiceUtils.isEnableExperimentalFeature(task, modelServiceLocator)) {
                LOGGER.trace(
                        "Skipping creating wrapper for container {} because it is experimental a experimental features are not enabled.",
                        def.getName());
                continue;
            }

            LOGGER.trace("ObjectWrapper.createContainerWrapper processing definition: {}", def);

            PrismContainerDefinition<C> containerDef = (PrismContainerDefinition) def;

            ItemPath newPath = createPropertyPath(parentPath, containerDef.getName());

            ContainerWrapperFactory cwf = new ContainerWrapperFactory(modelServiceLocator);

            PrismContainer<C> prismContainer = parentContainer.findContainer(def.getName());

            ContainerWrapper<C> container = createContainerWrapper(oWrapper.getObject(), oWrapper.getStatus(),
                    prismContainer, containerDef, cwf, newPath, task);
            result.addSubresult(cwf.getResult());
            if (container != null) {
                containerWrappers.add(container);
            }

        }
    }

    private <O extends ObjectType, C extends Containerable> ContainerWrapper<C> createContainerWrapper(
            PrismObject<O> object, ContainerStatus objectStatus, PrismContainer<C> prismContainer,
            PrismContainerDefinition<C> containerDef, ContainerWrapperFactory cwf, ItemPath newPath, Task task)
            throws SchemaException {
        if (ShadowAssociationType.COMPLEX_TYPE.equals(containerDef.getTypeName())) {
            ObjectType objectType = object.asObjectable();
            ShadowType shadow;
            if (objectType instanceof ShadowType) {
                shadow = (ShadowType) objectType;
            } else {
                throw new SchemaException("Something very strange happenned. Association contianer in the "
                        + objectType.getClass().getSimpleName() + "?");
            }
            //         Task task = modelServiceLocator.createSimpleTask("Load resource ref");
            //TODO: is it safe to case modelServiceLocator to pageBase?
            PrismObject<ResourceType> resource = WebModelServiceUtils.loadObject(shadow.getResourceRef(),
                    modelServiceLocator, task, result);

            result.computeStatusIfUnknown();
            if (!result.isAcceptable()) {
                LOGGER.error("Cannot find resource referenced from shadow. {}", result.getMessage());
                result.recordPartialError("Could not find resource referenced from shadow.");
                return null;
            }

            if (prismContainer != null) {
                return (ContainerWrapper<C>) cwf.createAssociationWrapper(resource, shadow.getKind(),
                        shadow.getIntent(), (PrismContainer<ShadowAssociationType>) prismContainer, objectStatus,
                        ContainerStatus.MODIFYING, newPath);
            }
            prismContainer = containerDef.instantiate();
            return (ContainerWrapper<C>) cwf.createAssociationWrapper(resource, shadow.getKind(),
                    shadow.getIntent(), (PrismContainer<ShadowAssociationType>) prismContainer, objectStatus,
                    ContainerStatus.ADDING, newPath);

        }

        if (prismContainer != null) {
            return cwf.createContainerWrapper(prismContainer, objectStatus, ContainerStatus.MODIFYING, newPath,
                    task);
        }

        prismContainer = containerDef.instantiate();
        return cwf.createContainerWrapper(prismContainer, objectStatus, ContainerStatus.ADDING, newPath, task);

    }

    private boolean isIgnoreContainer(QName containerDefinitionName) {
        for (QName container : CONTAINERS_TO_IGNORE) {
            if (container.equals(containerDefinitionName)) {
                return true;
            }
        }

        return false;
    }

    private ItemPath createPropertyPath(ItemPath path, QName element) {
        return path.append(element);
    }

    private boolean isShadow(PrismObject object) {
        return (object.getCompileTimeClass() != null
                && ShadowType.class.isAssignableFrom(object.getCompileTimeClass()))
                || (object.getDefinition() != null
                        && object.getDefinition().getName().equals(ShadowType.COMPLEX_TYPE));
    }
}