com.evolveum.midpoint.web.page.admin.PageAdminObjectDetails.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.web.page.admin.PageAdminObjectDetails.java

Source

/*
 * Copyright (c) 2010-2016 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.page.admin;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.xml.namespace.QName;

import com.evolveum.midpoint.model.api.context.ModelContext;
import org.apache.commons.lang.StringUtils;
import org.apache.wicket.Page;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.string.StringValue;

import com.evolveum.midpoint.gui.api.model.LoadableModel;
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.model.api.ModelExecuteOptions;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.RetrieveOption;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.ObjectTypes;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.QNameUtil;
import com.evolveum.midpoint.util.exception.AuthorizationException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
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.component.FocusSummaryPanel;
import com.evolveum.midpoint.web.component.objectdetails.AbstractObjectMainPanel;
import com.evolveum.midpoint.web.component.prism.ContainerStatus;
import com.evolveum.midpoint.web.component.prism.ObjectWrapper;
import com.evolveum.midpoint.web.component.prism.ObjectWrapperFactory;
import com.evolveum.midpoint.web.component.progress.ProgressReporter;
import com.evolveum.midpoint.web.component.progress.ProgressReportingAwarePage;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.page.admin.home.PageDashboard;
import com.evolveum.midpoint.web.page.admin.users.PageOrgTree;
import com.evolveum.midpoint.web.page.admin.users.dto.FocusSubwrapperDto;
import com.evolveum.midpoint.web.util.OnePageParameterEncoder;
import com.evolveum.midpoint.web.util.validation.MidpointFormValidator;
import com.evolveum.midpoint.web.util.validation.SimpleValidationError;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AdminGuiConfigurationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectFormType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectFormsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
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.UserType;
import org.apache.wicket.util.time.Duration;

/** 
 * @author semancik
 */
public abstract class PageAdminObjectDetails<O extends ObjectType> extends PageAdmin
        implements ProgressReportingAwarePage {
    private static final long serialVersionUID = 1L;

    private static final String DOT_CLASS = PageAdminObjectDetails.class.getName() + ".";

    public static final String PARAM_RETURN_PAGE = "returnPage";

    private static final String OPERATION_LOAD_OBJECT = DOT_CLASS + "loadObject";
    private static final String OPERATION_LOAD_PARENT_ORGS = DOT_CLASS + "loadParentOrgs";
    private static final String OPERATION_LOAD_GUI_CONFIGURATION = DOT_CLASS + "loadGuiConfiguration";
    protected static final String OPERATION_SAVE = DOT_CLASS + "save";
    protected static final String OPERATION_PREVIEW_CHANGES = DOT_CLASS + "previewChanges";
    protected static final String OPERATION_SEND_TO_SUBMIT = DOT_CLASS + "sendToSubmit";

    protected static final String ID_SUMMARY_PANEL = "summaryPanel";
    protected static final String ID_MAIN_PANEL = "mainPanel";

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

    private LoadableModel<ObjectWrapper<O>> objectModel;
    private LoadableModel<List<FocusSubwrapperDto<OrgType>>> parentOrgModel;

    private ProgressReporter progressReporter;

    // used to determine whether to leave this page or stay on it (after
    // operation finishing)
    private ObjectDelta<O> delta;

    private AbstractObjectMainPanel<O> mainPanel;
    private boolean saveOnConfigure; // ugly hack - whether to invoke 'Save' when returning to this page

    @Override
    protected void createBreadcrumb() {
        createInstanceBreadcrumb();
    }

    @Override
    protected void onConfigure() {
        super.onConfigure();
        if (saveOnConfigure) {
            saveOnConfigure = false;
            add(new AbstractAjaxTimerBehavior(Duration.milliseconds(100)) {
                @Override
                protected void onTimer(AjaxRequestTarget target) {
                    stop(target);
                    savePerformed(target);
                }
            });
        }
    }

    @Override
    protected IModel<String> createPageTitleModel() {
        return new LoadableModel<String>() {
            private static final long serialVersionUID = 1L;

            @Override
            protected String load() {
                if (!isEditingFocus()) {
                    String key = "PageAdminObjectDetails.title.new" + getCompileTimeClass().getSimpleName();
                    return createStringResource(key).getObject();
                }

                String name = null;
                if (getObjectWrapper() != null && getObjectWrapper().getObject() != null) {
                    name = WebComponentUtil.getName(getObjectWrapper().getObject());
                }

                String key = "PageAdminObjectDetails.title.edit" + getCompileTimeClass().getSimpleName();
                return createStringResource(key, name).getObject();
            }
        };
    }

    public LoadableModel<ObjectWrapper<O>> getObjectModel() {
        return objectModel;
    }

    public LoadableModel<List<FocusSubwrapperDto<OrgType>>> getParentOrgModel() {
        return parentOrgModel;
    }

    protected AbstractObjectMainPanel<O> getMainPanel() {
        return mainPanel;
    }

    public ObjectWrapper<O> getObjectWrapper() {
        return objectModel.getObject();
    }

    public List<FocusSubwrapperDto<OrgType>> getParentOrgs() {
        return parentOrgModel.getObject();
    }

    public ObjectDelta<O> getDelta() {
        return delta;
    }

    public void setDelta(ObjectDelta<O> delta) {
        this.delta = delta;
    }

    public ProgressReporter getProgressReporter() {
        return progressReporter;
    }

    protected void reviveModels() throws SchemaException {
        WebComponentUtil.revive(objectModel, getPrismContext());
        WebComponentUtil.revive(parentOrgModel, getPrismContext());
    }

    protected abstract Class<O> getCompileTimeClass();

    public void initialize(final PrismObject<O> objectToEdit) {
        initializeModel(objectToEdit);
        initLayout();
    }

    protected void initializeModel(final PrismObject<O> objectToEdit) {
        objectModel = new LoadableModel<ObjectWrapper<O>>(false) {
            private static final long serialVersionUID = 1L;

            @Override
            protected ObjectWrapper<O> load() {
                return loadObjectWrapper(objectToEdit);
            }
        };

        parentOrgModel = new LoadableModel<List<FocusSubwrapperDto<OrgType>>>(false) {
            private static final long serialVersionUID = 1L;

            @Override
            protected List<FocusSubwrapperDto<OrgType>> load() {
                return loadOrgWrappers();
            }
        };
    }

    protected List<FocusSubwrapperDto<OrgType>> loadOrgWrappers() {
        // WRONG!! TODO: fix
        return null;
    }

    protected abstract O createNewObject();

    protected void initLayout() {
        initLayoutSummaryPanel();

        mainPanel = createMainPanel(ID_MAIN_PANEL);
        mainPanel.setOutputMarkupId(true);
        add(mainPanel);

        progressReporter = createProgressReporter("progressPanel");
        add(progressReporter.getProgressPanel());
    }

    protected ProgressReporter createProgressReporter(String id) {
        return ProgressReporter.create(id, this);
    }

    protected abstract FocusSummaryPanel<O> createSummaryPanel();

    protected void initLayoutSummaryPanel() {

        FocusSummaryPanel<O> summaryPanel = createSummaryPanel();
        summaryPanel.setOutputMarkupId(true);

        summaryPanel.add(new VisibleEnableBehaviour() {
            private static final long serialVersionUID = 1L;

            @Override
            public boolean isVisible() {
                return isEditingFocus();
            }
        });

        add(summaryPanel);
    }

    protected abstract AbstractObjectMainPanel<O> createMainPanel(String id);

    protected String getObjectOidParameter() {
        PageParameters parameters = getPageParameters();
        LOGGER.trace("Page parameters: {}", parameters);
        StringValue oidValue = getPageParameters().get(OnePageParameterEncoder.PARAMETER);
        LOGGER.trace("OID parameter: {}", oidValue);
        if (oidValue == null) {
            return null;
        }
        String oid = oidValue.toString();
        if (StringUtils.isBlank(oid)) {
            return null;
        }
        return oid;
    }

    public boolean isEditingFocus() {
        return getObjectOidParameter() != null;
    }

    protected ObjectWrapper<O> loadObjectWrapper(PrismObject<O> objectToEdit) {
        Task task = createSimpleTask(OPERATION_LOAD_OBJECT);
        OperationResult result = task.getResult();
        PrismObject<O> object = null;
        Collection<SelectorOptions<GetOperationOptions>> loadOptions = null;
        try {
            if (!isEditingFocus()) {
                if (objectToEdit == null) {
                    LOGGER.trace("Loading object: New object (creating)");
                    O focusType = createNewObject();
                    getMidpointApplication().getPrismContext().adopt(focusType);
                    object = focusType.asPrismObject();
                } else {
                    LOGGER.trace("Loading object: New object (supplied): {}", objectToEdit);
                    object = objectToEdit;
                }
            } else {

                loadOptions = SelectorOptions.createCollection(UserType.F_JPEG_PHOTO,
                        GetOperationOptions.createRetrieve(RetrieveOption.INCLUDE));

                String focusOid = getObjectOidParameter();
                object = WebModelServiceUtils.loadObject(getCompileTimeClass(), focusOid, loadOptions, this, task,
                        result);

                LOGGER.trace("Loading object: Existing object (loadled): {} -> {}", focusOid, object);
            }

            result.recordSuccess();
        } catch (Exception ex) {
            result.recordFatalError("Couldn't get object.", ex);
            LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load object", ex);
        }

        showResult(result, false);

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

        if (object == null) {
            if (isEditingFocus()) {
                getSession().error(getString("pageAdminFocus.message.cantEditFocus"));
            } else {
                getSession().error(getString("pageAdminFocus.message.cantNewFocus"));
            }
            throw new RestartResponseException(getRestartResponsePage());
        }

        ContainerStatus status = isEditingFocus() ? ContainerStatus.MODIFYING : ContainerStatus.ADDING;
        ObjectWrapper<O> wrapper;
        ObjectWrapperFactory owf = new ObjectWrapperFactory(this);
        try {
            wrapper = owf.createObjectWrapper("pageAdminFocus.focusDetails", null, object, status);
        } catch (Exception ex) {
            result.recordFatalError("Couldn't get user.", ex);
            LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load user", ex);
            wrapper = owf.createObjectWrapper("pageAdminFocus.focusDetails", null, object, null, null, status,
                    false);
        }
        wrapper.setLoadOptions(loadOptions);

        showResult(wrapper.getResult(), false);

        loadParentOrgs(wrapper, task, result);

        wrapper.setShowEmpty(!isEditingFocus());

        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Loaded focus wrapper:\n{}", wrapper.debugDump());
        }

        return wrapper;
    }

    private void loadParentOrgs(ObjectWrapper<O> wrapper, Task task, OperationResult result) {
        OperationResult subResult = result.createMinorSubresult(OPERATION_LOAD_PARENT_ORGS);
        PrismObject<O> focus = wrapper.getObject();
        // Load parent organizations (full objects). There are used in the
        // summary panel and also in the main form.
        // Do it here explicitly instead of using resolve option to have ability
        // to better handle (ignore) errors.
        for (ObjectReferenceType parentOrgRef : focus.asObjectable().getParentOrgRef()) {

            PrismObject<OrgType> parentOrg = null;
            try {

                parentOrg = getModelService().getObject(OrgType.class, parentOrgRef.getOid(), null, task,
                        subResult);
                LOGGER.trace("Loaded parent org with result {}", new Object[] { subResult.getLastSubresult() });
            } catch (AuthorizationException e) {
                // This can happen if the user has permission to read parentOrgRef but it does not have
                // the permission to read target org
                // It is OK to just ignore it.
                subResult.muteLastSubresultError();
                LOGGER.debug("User {} does not have permission to read parent org unit {} (ignoring error)",
                        task.getOwner().getName(), parentOrgRef.getOid());
            } catch (Exception ex) {
                subResult.recordWarning("Cannot load parent org " + parentOrgRef.getOid(), ex);
                LOGGER.warn("Cannot load parent org {}: {}", parentOrgRef.getOid(), ex.getMessage(), ex);
            }

            if (parentOrg != null) {
                wrapper.getParentOrgs().add(parentOrg);
            }
        }
        subResult.computeStatus();
    }

    protected abstract Class<? extends Page> getRestartResponsePage();

    public Object findParam(String param, String oid, OperationResult result) {

        Object object = null;

        for (OperationResult subResult : result.getSubresults()) {
            if (subResult != null && subResult.getParams() != null) {
                if (subResult.getParams().get(param) != null
                        && subResult.getParams().get(OperationResult.PARAM_OID) != null
                        && subResult.getParams().get(OperationResult.PARAM_OID).equals(oid)) {
                    return subResult.getParams().get(param);
                }
                object = findParam(param, oid, subResult);

            }
        }
        return object;
    }

    // TODO put this into correct place
    protected boolean previewRequested;

    /**
     * This will be called from the main form when save button is pressed.
     */
    public void savePerformed(AjaxRequestTarget target) {
        progressReporter.onSaveSubmit();
        OperationResult result = new OperationResult(OPERATION_SAVE);
        previewRequested = false;
        saveOrPreviewPerformed(target, result, false);
    }

    public void previewPerformed(AjaxRequestTarget target) {
        progressReporter.onSaveSubmit();
        OperationResult result = new OperationResult(OPERATION_PREVIEW_CHANGES);
        previewRequested = true;
        saveOrPreviewPerformed(target, result, true);
    }

    public void saveOrPreviewPerformed(AjaxRequestTarget target, OperationResult result, boolean previewOnly) {
        ObjectWrapper<O> objectWrapper = getObjectWrapper();
        LOGGER.debug("Saving object {}", objectWrapper);

        // todo: improve, delta variable is quickfix for MID-1006
        // redirecting to user list page everytime user is created in repository
        // during user add in gui,
        // and we're not taking care about account/assignment create errors
        // (error message is still displayed)
        delta = null;

        Task task = createSimpleTask(OPERATION_SEND_TO_SUBMIT);

        ModelExecuteOptions options = getExecuteChangesOptions();
        LOGGER.debug("Using execute options {}.", new Object[] { options });

        try {
            reviveModels();

            delta = objectWrapper.getObjectDelta();
            if (objectWrapper.getOldDelta() != null) {
                delta = ObjectDelta.summarize(objectWrapper.getOldDelta(), delta);
            }
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("User delta computed from form:\n{}", new Object[] { delta.debugDump(3) });
            }
        } catch (Exception ex) {
            result.recordFatalError(getString("pageUser.message.cantCreateUser"), ex);
            LoggingUtils.logUnexpectedException(LOGGER, "Create user failed", ex);
            showResult(result);
            return;
        }

        switch (objectWrapper.getStatus()) {
        case ADDING:
            try {
                PrismObject<O> objectToAdd = delta.getObjectToAdd();
                WebComponentUtil.encryptCredentials(objectToAdd, true, getMidpointApplication());
                prepareObjectForAdd(objectToAdd);
                getPrismContext().adopt(objectToAdd, getCompileTimeClass());
                if (LOGGER.isTraceEnabled()) {
                    LOGGER.trace("Delta before add user:\n{}", new Object[] { delta.debugDump(3) });
                }

                if (!delta.isEmpty()) {
                    delta.revive(getPrismContext());

                    final Collection<ObjectDelta<? extends ObjectType>> deltas = WebComponentUtil
                            .createDeltaCollection(delta);
                    final Collection<SimpleValidationError> validationErrors = performCustomValidation(objectToAdd,
                            deltas);
                    if (checkValidationErrors(target, validationErrors)) {
                        return;
                    }
                    progressReporter.executeChanges(deltas, previewOnly, options, task, result, target);
                } else {
                    result.recordSuccess();
                }
            } catch (Exception ex) {
                result.recordFatalError(getString("pageFocus.message.cantCreateFocus"), ex);
                LoggingUtils.logUnexpectedException(LOGGER, "Create user failed", ex);
                showResult(result);
            }
            break;

        case MODIFYING:
            try {
                WebComponentUtil.encryptCredentials(delta, true, getMidpointApplication());
                prepareObjectDeltaForModify(delta);

                if (LOGGER.isTraceEnabled()) {
                    LOGGER.trace("Delta before modify user:\n{}", new Object[] { delta.debugDump(3) });
                }

                Collection<ObjectDelta<? extends ObjectType>> deltas = new ArrayList<>();
                if (!delta.isEmpty()) {
                    delta.revive(getPrismContext());
                    deltas.add(delta);
                }

                List<ObjectDelta<? extends ObjectType>> additionalDeltas = getAdditionalModifyDeltas(result);
                if (additionalDeltas != null) {
                    for (ObjectDelta additionalDelta : additionalDeltas) {
                        if (!additionalDelta.isEmpty()) {
                            additionalDelta.revive(getPrismContext());
                            deltas.add(additionalDelta);
                        }
                    }
                }

                if (delta.isEmpty() && ModelExecuteOptions.isReconcile(options)) {
                    ObjectDelta emptyDelta = ObjectDelta.createEmptyModifyDelta(getCompileTimeClass(),
                            objectWrapper.getObject().getOid(), getPrismContext());
                    deltas.add(emptyDelta);

                    Collection<SimpleValidationError> validationErrors = performCustomValidation(null, deltas);
                    if (checkValidationErrors(target, validationErrors)) {
                        return;
                    }
                    progressReporter.executeChanges(deltas, previewOnly, options, task, result, target);
                } else if (!deltas.isEmpty()) {
                    Collection<SimpleValidationError> validationErrors = performCustomValidation(null, deltas);
                    if (checkValidationErrors(target, validationErrors)) {
                        return;
                    }
                    progressReporter.executeChanges(deltas, previewOnly, options, task, result, target);
                } else {
                    progressReporter.clearProgressPanel(); // from previous attempts (useful only if we would call finishProcessing at the end, but that's not the case now)
                    if (!previewOnly) {
                        result.recordWarning(getString("PageAdminObjectDetails.noChangesSave"));
                        showResult(result);
                        redirectBack();
                    } else {
                        warn(getString("PageAdminObjectDetails.noChangesPreview"));
                        target.add(getFeedbackPanel());
                    }
                }

            } catch (Exception ex) {
                if (!executeForceDelete(objectWrapper, task, options, result)) {
                    result.recordFatalError(getString("pageUser.message.cantUpdateUser"), ex);
                    LoggingUtils.logUnexpectedException(LOGGER, getString("pageUser.message.cantUpdateUser"), ex);
                } else {
                    result.recomputeStatus();
                }
                showResult(result);
            }
            break;
        // support for add/delete containers (e.g. delete credentials)
        default:
            error(getString("pageAdminFocus.message.unsupportedState", objectWrapper.getStatus()));
        }

        //      result.recomputeStatus();
        //
        //      if (!result.isInProgress()) {
        //         LOGGER.trace("Result NOT in progress, calling finishProcessing");
        //         finishProcessing(target, result, false);
        //      }

        LOGGER.trace("returning from saveOrPreviewPerformed");
    }

    protected boolean checkValidationErrors(AjaxRequestTarget target,
            Collection<SimpleValidationError> validationErrors) {
        if (validationErrors != null && !validationErrors.isEmpty()) {
            for (SimpleValidationError error : validationErrors) {
                LOGGER.error("Validation error, attribute: '" + error.printAttribute() + "', message: '"
                        + error.getMessage() + "'.");
                error("Validation error, attribute: '" + error.printAttribute() + "', message: '"
                        + error.getMessage() + "'.");
            }

            target.add(getFeedbackPanel());
            return true;
        }
        return false;
    }

    @Override
    public void startProcessing(AjaxRequestTarget target, OperationResult result) {
        LOGGER.trace("startProcessing called, making main panel invisible");
        mainPanel.setVisible(false);
        target.add(mainPanel);
    }

    protected ModelExecuteOptions getExecuteChangesOptions() {
        return mainPanel.getExecuteChangeOptionsDto().createOptions();
    }

    protected void prepareObjectForAdd(PrismObject<O> object) throws SchemaException {

    }

    protected void prepareObjectDeltaForModify(ObjectDelta<O> objectDelta) throws SchemaException {

    }

    protected List<ObjectDelta<? extends ObjectType>> getAdditionalModifyDeltas(OperationResult result) {
        return null;
    }

    protected boolean executeForceDelete(ObjectWrapper userWrapper, Task task, ModelExecuteOptions options,
            OperationResult parentResult) {
        return isForce();
    }

    protected boolean isForce() {
        return getMainPanel().getExecuteChangeOptionsDto().isForce();
    }

    protected boolean isKeepDisplayingResults() {
        return getMainPanel().getExecuteChangeOptionsDto().isKeepDisplayingResults();
    }

    protected Collection<SimpleValidationError> performCustomValidation(PrismObject<O> object,
            Collection<ObjectDelta<? extends ObjectType>> deltas) throws SchemaException {
        Collection<SimpleValidationError> errors = null;

        if (object == null) {
            if (getObjectWrapper() != null && getObjectWrapper().getObject() != null) {
                object = getObjectWrapper().getObject().clone(); // otherwise original object could get corrupted e.g. by applying the delta below

                for (ObjectDelta delta : deltas) {
                    // because among deltas there can be also ShadowType deltas
                    if (UserType.class.isAssignableFrom(delta.getObjectTypeClass())) {
                        delta.applyTo(object);
                    }
                }
            }
        } else {
            object = object.clone();
        }

        performAdditionalValidation(object, deltas, errors);

        for (MidpointFormValidator validator : getFormValidatorRegistry().getValidators()) {
            if (errors == null) {
                errors = validator.validateObject(object, deltas);
            } else {
                errors.addAll(validator.validateObject(object, deltas));
            }
        }

        return errors;
    }

    protected void performAdditionalValidation(PrismObject<O> object,
            Collection<ObjectDelta<? extends ObjectType>> deltas, Collection<SimpleValidationError> errors)
            throws SchemaException {

    }

    public List<ObjectFormType> getObjectFormTypes() {
        Task task = createSimpleTask(OPERATION_LOAD_GUI_CONFIGURATION);
        OperationResult result = task.getResult();
        AdminGuiConfigurationType adminGuiConfiguration;
        try {
            adminGuiConfiguration = getModelInteractionService().getAdminGuiConfiguration(task, result);
        } catch (ObjectNotFoundException | SchemaException e) {
            throw new SystemException("Cannot load GUI configuration: " + e.getMessage(), e);
        }
        if (adminGuiConfiguration == null) {
            return null;
        }
        ObjectFormsType objectFormsType = adminGuiConfiguration.getObjectForms();
        if (objectFormsType == null) {
            return null;
        }
        List<ObjectFormType> objectForms = objectFormsType.getObjectForm();
        if (objectForms == null || objectForms.isEmpty()) {
            return objectForms;
        }
        List<ObjectFormType> validObjectForms = new ArrayList<>();
        for (ObjectFormType objectForm : objectForms) {
            if (isSupportedObjectType(objectForm.getType())) {
                validObjectForms.add(objectForm);
            }
        }
        return validObjectForms;
    }

    protected boolean isSupportedObjectType(QName type) {
        ObjectTypes objectType = ObjectTypes.getObjectType(getCompileTimeClass());
        return QNameUtil.match(objectType.getTypeQName(), type);
    }

    public void setSaveOnConfigure(boolean saveOnConfigure) {
        this.saveOnConfigure = saveOnConfigure;
    }

    public boolean isSaveOnConfigure() {
        return saveOnConfigure;
    }
}