com.evolveum.midpoint.gui.api.util.WebComponentUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.gui.api.util.WebComponentUtil.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.gui.api.util;

import static com.evolveum.midpoint.gui.api.page.PageBase.createStringResourceStatic;
import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.normalizeRelation;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

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

import com.evolveum.midpoint.common.refinery.RefinedAssociationDefinition;
import com.evolveum.midpoint.gui.api.SubscriptionType;
import com.evolveum.midpoint.gui.api.model.ReadOnlyValueModel;
import com.evolveum.midpoint.model.api.ModelExecuteOptions;
import com.evolveum.midpoint.prism.query.*;
import com.evolveum.midpoint.prism.query.builder.S_FilterEntryOrEmpty;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.util.LocalizationUtil;
import com.evolveum.midpoint.util.*;
import com.evolveum.midpoint.web.component.data.SelectableBeanObjectDataProvider;
import com.evolveum.midpoint.web.component.prism.*;
import com.evolveum.midpoint.web.util.ObjectTypeGuiDescriptor;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.validator.routines.checkdigit.VerhoeffCheckDigit;
import org.apache.wicket.*;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
import org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;
import org.apache.wicket.authroles.authorization.strategies.role.Roles;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
import org.apache.wicket.datetime.PatternDateConverter;
import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
import org.apache.wicket.extensions.markup.html.tabs.ITab;
import org.apache.wicket.feedback.IFeedback;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.*;
import org.apache.wicket.markup.repeater.data.IDataProvider;
import org.apache.wicket.model.*;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.string.StringValue;
import org.apache.wicket.util.visit.IVisit;
import org.apache.wicket.util.visit.IVisitor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joda.time.format.DateTimeFormat;

import com.evolveum.midpoint.gui.api.GuiStyleConstants;
import com.evolveum.midpoint.gui.api.component.MainObjectListPanel;
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.gui.api.model.NonEmptyModel;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.prism.Containerable;
import com.evolveum.midpoint.prism.Objectable;
import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.Revivable;
import com.evolveum.midpoint.prism.crypto.EncryptionException;
import com.evolveum.midpoint.prism.crypto.Protector;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.delta.PropertyDelta;
import com.evolveum.midpoint.prism.match.DefaultMatchingRule;
import com.evolveum.midpoint.prism.match.DistinguishedNameMatchingRule;
import com.evolveum.midpoint.prism.match.ExchangeEmailAddressesMatchingRule;
import com.evolveum.midpoint.prism.match.PolyStringNormMatchingRule;
import com.evolveum.midpoint.prism.match.PolyStringOrigMatchingRule;
import com.evolveum.midpoint.prism.match.PolyStringStrictMatchingRule;
import com.evolveum.midpoint.prism.match.StringIgnoreCaseMatchingRule;
import com.evolveum.midpoint.prism.match.UuidMatchingRule;
import com.evolveum.midpoint.prism.match.XmlMatchingRule;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.ItemPathSegment;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.query.builder.QueryBuilder;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.schema.DeltaConvertor;
import com.evolveum.midpoint.schema.SchemaConstantsGenerated;
import com.evolveum.midpoint.schema.constants.ObjectTypes;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.schema.util.ResourceTypeUtil;
import com.evolveum.midpoint.schema.util.ShadowUtil;
import com.evolveum.midpoint.security.api.AuthorizationConstants;
import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.task.api.TaskCategory;
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.TabbedPanel;
import com.evolveum.midpoint.web.component.data.BaseSortableDataProvider;
import com.evolveum.midpoint.web.component.data.Table;
import com.evolveum.midpoint.web.component.data.column.ColumnMenuAction;
import com.evolveum.midpoint.web.component.input.DisplayableValueChoiceRenderer;
import com.evolveum.midpoint.web.component.input.DropDownChoicePanel;
import com.evolveum.midpoint.web.component.util.Selectable;
import com.evolveum.midpoint.web.component.util.SelectableBean;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.page.PageDialog;
import com.evolveum.midpoint.web.page.admin.configuration.component.EmptyOnBlurAjaxFormUpdatingBehaviour;
import com.evolveum.midpoint.web.page.admin.configuration.component.EmptyOnChangeAjaxFormUpdatingBehavior;
import com.evolveum.midpoint.web.page.admin.reports.PageReport;
import com.evolveum.midpoint.web.page.admin.reports.PageReports;
import com.evolveum.midpoint.web.page.admin.resources.PageResource;
import com.evolveum.midpoint.web.page.admin.resources.PageResources;
import com.evolveum.midpoint.web.page.admin.roles.PageRole;
import com.evolveum.midpoint.web.page.admin.roles.PageRoles;
import com.evolveum.midpoint.web.page.admin.server.PageTaskEdit;
import com.evolveum.midpoint.web.page.admin.server.dto.OperationResultStatusPresentationProperties;
import com.evolveum.midpoint.web.page.admin.services.PageService;
import com.evolveum.midpoint.web.page.admin.services.PageServices;
import com.evolveum.midpoint.web.page.admin.users.PageOrgUnit;
import com.evolveum.midpoint.web.page.admin.users.PageUser;
import com.evolveum.midpoint.web.page.admin.users.PageUsers;
import com.evolveum.midpoint.web.security.MidPointApplication;
import com.evolveum.midpoint.web.security.SecurityUtils;
import com.evolveum.midpoint.web.session.SessionStorage;
import com.evolveum.midpoint.web.session.UserProfileStorage.TableId;
import com.evolveum.midpoint.web.util.DateValidator;
import com.evolveum.midpoint.web.util.InfoTooltipBehavior;
import com.evolveum.midpoint.web.util.OnePageParameterEncoder;
import com.evolveum.prism.xml.ns._public.query_3.QueryType;
import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;
import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;

/**
 * Utility class containing miscellaneous methods used mostly in Wicket
 * components.
 *
 * @author lazyman
 */
public final class WebComponentUtil {

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

    private static final String KEY_BOOLEAN_NULL = "Boolean.NULL";
    private static final String KEY_BOOLEAN_TRUE = "Boolean.TRUE";
    private static final String KEY_BOOLEAN_FALSE = "Boolean.FALSE";

    private static DatatypeFactory df = null;

    private static Map<Class<?>, Class<? extends PageBase>> objectDetailsPageMap;

    static {
        objectDetailsPageMap = new HashMap<>();
        objectDetailsPageMap.put(UserType.class, PageUser.class);
        objectDetailsPageMap.put(OrgType.class, PageOrgUnit.class);
        objectDetailsPageMap.put(RoleType.class, PageRole.class);
        objectDetailsPageMap.put(ServiceType.class, PageService.class);
        objectDetailsPageMap.put(ResourceType.class, PageResource.class);
        objectDetailsPageMap.put(TaskType.class, PageTaskEdit.class);
        objectDetailsPageMap.put(ReportType.class, PageReport.class);
    }

    // only pages that support 'advanced search' are currently listed here (TODO: generalize)
    private static Map<Class<?>, Class<? extends PageBase>> objectListPageMap;

    static {
        objectListPageMap = new HashMap<>();
        objectListPageMap.put(UserType.class, PageUsers.class);
        objectListPageMap.put(RoleType.class, PageRoles.class);
        objectListPageMap.put(ServiceType.class, PageServices.class);
        objectListPageMap.put(ResourceType.class, PageResources.class);
    }

    private static Map<Class<?>, String> storageKeyMap;

    static {
        storageKeyMap = new HashMap<>();
        storageKeyMap.put(PageUsers.class, SessionStorage.KEY_USERS);
        storageKeyMap.put(PageResources.class, SessionStorage.KEY_RESOURCES);
        storageKeyMap.put(PageReports.class, SessionStorage.KEY_REPORTS);
        storageKeyMap.put(PageRoles.class, SessionStorage.KEY_ROLES);
        storageKeyMap.put(PageServices.class, SessionStorage.KEY_SERVICES);
    }

    private static Map<TableId, String> storageTableIdMap;

    static {
        storageTableIdMap = new HashMap<>();
        storageTableIdMap.put(TableId.PAGE_RESOURCE_ACCOUNTS_PANEL_REPOSITORY_MODE,
                SessionStorage.KEY_RESOURCE_ACCOUNT_CONTENT + SessionStorage.KEY_RESOURCE_PAGE_REPOSITORY_CONTENT);
        storageTableIdMap.put(TableId.PAGE_RESOURCE_ACCOUNTS_PANEL_RESOURCE_MODE,
                SessionStorage.KEY_RESOURCE_ACCOUNT_CONTENT + SessionStorage.KEY_RESOURCE_PAGE_RESOURCE_CONTENT);
        storageTableIdMap.put(TableId.PAGE_RESOURCE_ENTITLEMENT_PANEL_REPOSITORY_MODE,
                SessionStorage.KEY_RESOURCE_ENTITLEMENT_CONTENT
                        + SessionStorage.KEY_RESOURCE_PAGE_REPOSITORY_CONTENT);
        storageTableIdMap.put(TableId.PAGE_RESOURCE_ENTITLEMENT_PANEL_RESOURCE_MODE,
                SessionStorage.KEY_RESOURCE_ENTITLEMENT_CONTENT
                        + SessionStorage.KEY_RESOURCE_PAGE_RESOURCE_CONTENT);
        storageTableIdMap.put(TableId.PAGE_RESOURCE_GENERIC_PANEL_REPOSITORY_MODE,
                SessionStorage.KEY_RESOURCE_GENERIC_CONTENT + SessionStorage.KEY_RESOURCE_PAGE_REPOSITORY_CONTENT);
        storageTableIdMap.put(TableId.PAGE_RESOURCE_GENERIC_PANEL_RESOURCE_MODE,
                SessionStorage.KEY_RESOURCE_GENERIC_CONTENT + SessionStorage.KEY_RESOURCE_PAGE_RESOURCE_CONTENT);
        storageTableIdMap.put(TableId.PAGE_RESOURCE_OBJECT_CLASS_PANEL,
                SessionStorage.KEY_RESOURCE_OBJECT_CLASS_CONTENT);

    }

    public static String nl2br(String text) {
        if (text == null) {
            return null;
        }
        return StringEscapeUtils.escapeHtml4(text).replace("\n", "<br/>");
    }

    public static String getTypeLocalized(ObjectReferenceType ref) {
        ObjectTypes type = ref != null ? ObjectTypes.getObjectTypeFromTypeQName(ref.getType()) : null;
        ObjectTypeGuiDescriptor descriptor = ObjectTypeGuiDescriptor.getDescriptor(type);
        if (descriptor == null) {
            return null;
        }
        return createStringResourceStatic(null, descriptor.getLocalizationKey()).getString();
    }

    public static String getReferencedObjectNames(List<ObjectReferenceType> refs, boolean showTypes) {
        return refs.stream()
                .map(ref -> emptyIfNull(getName(ref))
                        + (showTypes ? (" (" + emptyIfNull(getTypeLocalized(ref)) + ")") : ""))
                .collect(Collectors.joining(", "));
    }

    private static String emptyIfNull(String s) {
        return s != null ? s : "";
    }

    public static String getReferencedObjectDisplayNamesAndNames(List<ObjectReferenceType> refs,
            boolean showTypes) {
        return refs.stream()
                .map(ref -> emptyIfNull(getDisplayNameAndName(ref))
                        + (showTypes ? (" (" + emptyIfNull(getTypeLocalized(ref)) + ")") : ""))
                .collect(Collectors.joining(", "));
    }

    public static void addAjaxOnUpdateBehavior(WebMarkupContainer container) {
        container.visitChildren(new IVisitor<Component, Object>() {
            @Override
            public void component(Component component, IVisit<Object> objectIVisit) {
                if (component instanceof InputPanel) {
                    addAjaxOnBlurUpdateBehaviorToComponent(((InputPanel) component).getBaseFormComponent());
                } else if (component instanceof FormComponent) {
                    addAjaxOnBlurUpdateBehaviorToComponent(component);
                }
            }
        });
    }

    private static void addAjaxOnBlurUpdateBehaviorToComponent(final Component component) {
        component.setOutputMarkupId(true);
        component.add(new AjaxFormComponentUpdatingBehavior("blur") {

            @Override
            protected void onUpdate(AjaxRequestTarget target) {
            }
        });
    }

    public static String resolveLocalizableMessage(LocalizableMessageType localizableMessage, Component component) {
        if (localizableMessage == null) {
            return null;
        }
        return resolveLocalizableMessage(LocalizationUtil.toLocalizableMessage(localizableMessage), component);
    }

    public static String resolveLocalizableMessage(LocalizableMessage localizableMessage, Component component) {
        if (localizableMessage == null) {
            return null;
        } else if (localizableMessage instanceof SingleLocalizableMessage) {
            return resolveLocalizableMessage((SingleLocalizableMessage) localizableMessage, component);
        } else if (localizableMessage instanceof LocalizableMessageList) {
            return resolveLocalizableMessage((LocalizableMessageList) localizableMessage, component);
        } else {
            throw new AssertionError("Unsupported localizable message type: " + localizableMessage);
        }
    }

    private static String resolveLocalizableMessage(SingleLocalizableMessage localizableMessage,
            Component component) {
        if (localizableMessage == null) {
            return null;
        }
        while (localizableMessage.getFallbackLocalizableMessage() != null) {
            if (localizableMessage.getKey() != null) {
                Localizer localizer = Application.get().getResourceSettings().getLocalizer();
                if (localizer.getStringIgnoreSettings(localizableMessage.getKey(), component, null, null) != null) {
                    break; // the key exists => we can use the current localizableMessage
                }
            }
            if (localizableMessage.getFallbackLocalizableMessage() instanceof SingleLocalizableMessage) {
                localizableMessage = (SingleLocalizableMessage) localizableMessage.getFallbackLocalizableMessage();
            } else {
                return resolveLocalizableMessage(localizableMessage.getFallbackLocalizableMessage(), component);
            }
        }
        String key = localizableMessage.getKey() != null ? localizableMessage.getKey()
                : localizableMessage.getFallbackMessage();
        StringResourceModel stringResourceModel = new StringResourceModel(key, component)
                .setModel(new Model<String>()).setDefaultValue(localizableMessage.getFallbackMessage())
                .setParameters(resolveArguments(localizableMessage.getArgs(), component));
        String rv = stringResourceModel.getString();
        //System.out.println("GUI: Resolving [" + key + "]: to [" + rv + "]");
        return rv;
    }

    // todo deduplicate with similar method in LocalizationServiceImpl
    private static String resolveLocalizableMessage(LocalizableMessageList msgList, Component component) {
        String separator = resolveIfPresent(msgList.getSeparator(), component);
        String prefix = resolveIfPresent(msgList.getPrefix(), component);
        String suffix = resolveIfPresent(msgList.getPostfix(), component);
        return msgList.getMessages().stream().map(m -> resolveLocalizableMessage(m, component))
                .collect(Collectors.joining(separator, prefix, suffix));
    }

    private static String resolveIfPresent(LocalizableMessage msg, Component component) {
        return msg != null ? resolveLocalizableMessage(msg, component) : "";
    }

    private static Object[] resolveArguments(Object[] args, Component component) {
        if (args == null) {
            return null;
        }
        Object[] rv = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof LocalizableMessage) {
                rv[i] = resolveLocalizableMessage(((LocalizableMessage) args[i]), component);
            } else {
                rv[i] = args[i];
            }
        }
        return rv;
    }

    // TODO add other classes; probably move to some enum
    @Nullable
    public static String getAuthorizationActionForTargetClass(Class targetClass) {
        if (UserType.class.equals(targetClass)) {
            return AuthorizationConstants.AUTZ_UI_USER_URL;
        } else if (OrgType.class.equals(targetClass)) {
            return AuthorizationConstants.AUTZ_UI_ORG_UNIT_URL;
        } else if (RoleType.class.equals(targetClass)) {
            return AuthorizationConstants.AUTZ_UI_ROLE_URL;
        } else if (ServiceType.class.equals(targetClass)) {
            return AuthorizationConstants.AUTZ_UI_SERVICE_URL;
        } else if (ResourceType.class.equals(targetClass)) {
            return AuthorizationConstants.AUTZ_UI_RESOURCE_URL;
        } else {
            return null;
        }
    }

    // quite a hack (temporary)
    public static <T extends ObjectType> IModel<ObjectWrapper<T>> adopt(
            PropertyModel<ObjectWrapper<T>> objectWrapperModel, PrismContext prismContext) {
        if (objectWrapperModel == null) {
            return null;
        }
        ObjectWrapper<T> wrapper = objectWrapperModel.getObject();
        if (wrapper == null || wrapper.getObject() == null) {
            return objectWrapperModel;
        }
        try {
            prismContext.adopt(wrapper.getObject());
        } catch (SchemaException e) {
            throw new IllegalStateException("Unexpected SchemaException: " + e.getMessage());
        }
        return objectWrapperModel;
    }

    public static void safeResultCleanup(OperationResult result, Trace logger) {
        try {
            result.cleanupResultDeeply();
        } catch (Throwable t) {
            LoggingUtils.logUnexpectedException(logger, "Couldn't clean up the operation result", t);
        }
    }

    public static GuiObjectListViewType getDefaultGuiObjectListType(PageBase pageBase) {
        AdminGuiConfigurationType config = pageBase.getPrincipal().getAdminGuiConfiguration();
        if (config == null) {
            return null;
        }
        GuiObjectListViewsType lists = config.getObjectLists();
        if (lists == null) {
            return null;
        }
        return lists.getDefault();
    }

    public enum Channel {
        // TODO: move this to schema component
        LIVE_SYNC(SchemaConstants.CHANGE_CHANNEL_LIVE_SYNC_URI), RECONCILIATION(
                SchemaConstants.CHANGE_CHANNEL_RECON_URI), DISCOVERY(
                        SchemaConstants.CHANGE_CHANNEL_DISCOVERY_URI), WEB_SERVICE(
                                SchemaConstants.CHANNEL_WEB_SERVICE_URI), IMPORT(
                                        SchemaConstants.CHANNEL_OBJECT_IMPORT_URI), REST(
                                                SchemaConstants.CHANNEL_REST_URI), INIT(
                                                        SchemaConstants.CHANNEL_GUI_INIT_URI), USER(
                                                                SchemaConstants.CHANNEL_GUI_USER_URI), SELF_REGISTRATION(
                                                                        SchemaConstants.CHANNEL_GUI_SELF_REGISTRATION_URI), RESET_PASSWORD(
                                                                                SchemaConstants.CHANNEL_GUI_RESET_PASSWORD_URI);

        private String channel;

        Channel(String channel) {
            this.channel = channel;
        }

        public String getChannel() {
            return channel;
        }
    }

    static {
        try {
            df = DatatypeFactory.newInstance();
        } catch (DatatypeConfigurationException dce) {
            throw new IllegalStateException("Exception while obtaining Datatype Factory instance", dce);
        }
    }

    public static DateValidator getRangeValidator(Form<?> form, ItemPath path) {
        DateValidator validator = null;
        List<DateValidator> validators = form.getBehaviors(DateValidator.class);
        if (validators != null) {
            for (DateValidator val : validators) {
                if (path.equivalent(val.getIdentifier())) {
                    validator = val;
                    break;
                }
            }
        }

        if (validator == null) {
            validator = new DateValidator();
            validator.setIdentifier(path);
            form.add(validator);
        }

        return validator;
    }

    public static boolean isItemVisible(List<ItemPath> visibleItems, ItemPath itemToBeFound) {
        return ItemPath.containsSubpathOrEquivalent(visibleItems, itemToBeFound);

    }

    public static Class<?> qnameToClass(PrismContext prismContext, QName type) {
        return prismContext.getSchemaRegistry().determineCompileTimeClass(type);
    }

    public static <T extends ObjectType> Class<T> qnameToClass(PrismContext prismContext, QName type,
            Class<T> returnType) {
        return returnType = prismContext.getSchemaRegistry().determineCompileTimeClass(type);
    }

    public static <T extends ObjectType> QName classToQName(PrismContext prismContext, Class<T> clazz) {
        return prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(clazz).getTypeName();
    }

    public static TaskType createSingleRecurrenceTask(String taskName, QName applicableType, ObjectQuery query,
            ObjectDelta delta, ModelExecuteOptions options, String category, PageBase pageBase)
            throws SchemaException {

        TaskType task = new TaskType();

        MidPointPrincipal owner = SecurityUtils.getPrincipalUser();

        ObjectReferenceType ownerRef = new ObjectReferenceType();
        ownerRef.setOid(owner.getOid());
        ownerRef.setType(owner.getUser().COMPLEX_TYPE);
        task.setOwnerRef(ownerRef);

        task.setBinding(TaskBindingType.LOOSE);
        task.setCategory(category);
        task.setExecutionStatus(TaskExecutionStatusType.RUNNABLE);
        task.setRecurrence(TaskRecurrenceType.SINGLE);
        task.setThreadStopAction(ThreadStopActionType.RESTART);
        task.setHandlerUri(pageBase.getTaskService().getHandlerUriForCategory(category));
        ScheduleType schedule = new ScheduleType();
        schedule.setMisfireAction(MisfireActionType.EXECUTE_IMMEDIATELY);
        task.setSchedule(schedule);

        task.setName(WebComponentUtil.createPolyFromOrigString(taskName));

        PrismObject<TaskType> prismTask = task.asPrismObject();
        ItemPath path = new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_OBJECT_QUERY);
        PrismProperty objectQuery = prismTask.findOrCreateProperty(path);
        QueryType queryType = QueryJaxbConvertor.createQueryType(query, pageBase.getPrismContext());
        objectQuery.addRealValue(queryType);

        path = new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_OBJECT_TYPE);
        PrismProperty objectType = prismTask.findOrCreateProperty(path);
        objectType.setRealValue(applicableType);

        if (delta != null) {
            path = new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_OBJECT_DELTA);
            PrismProperty objectDelta = prismTask.findOrCreateProperty(path);
            objectDelta.setRealValue(DeltaConvertor.toObjectDeltaType(delta));
        }

        if (options != null) {
            prismTask
                    .findOrCreateProperty(
                            new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_EXECUTE_OPTIONS))
                    .setRealValue(options.toModelExecutionOptionsType());
        }

        return task;

    }

    public static boolean isAuthorized(String... action) {
        if (action == null || action.length == 0) {
            return true;
        }
        List<String> actions = Arrays.asList(action);
        return isAuthorized(actions);
    }

    public static boolean isAuthorized(Collection<String> actions) {
        if (actions == null || actions.isEmpty()) {
            return true;
        }
        Roles roles = new Roles(AuthorizationConstants.AUTZ_ALL_URL);
        roles.add(AuthorizationConstants.AUTZ_GUI_ALL_URL);
        roles.add(AuthorizationConstants.AUTZ_GUI_ALL_DEPRECATED_URL);
        roles.addAll(actions);
        if (((AuthenticatedWebApplication) AuthenticatedWebApplication.get()).hasAnyRole(roles)) {
            return true;
        }
        return false;
    }

    // TODO: move to util component
    public static Integer safeLongToInteger(Long l) {
        if (l == null) {
            return null;
        }

        if (l > Integer.MAX_VALUE || l < Integer.MIN_VALUE) {
            throw new IllegalArgumentException("Couldn't transform long '" + l + "' to int, too big or too small.");
        }

        return (int) l.longValue();
    }

    // TODO: move to schema component
    public static List<QName> createObjectTypeList() {

        List<QName> types = new ArrayList<>(ObjectTypes.values().length);
        for (ObjectTypes t : ObjectTypes.values()) {
            types.add(t.getTypeQName());
        }

        return types.stream().sorted((type1, type2) -> {
            Validate.notNull(type1);
            Validate.notNull(type2);

            return String.CASE_INSENSITIVE_ORDER.compare(QNameUtil.qNameToUri(type1), QNameUtil.qNameToUri(type2));

        }).collect(Collectors.toList());

    }

    // TODO: move to schema component
    public static List<QName> createFocusTypeList() {
        List<QName> focusTypeList = new ArrayList<>();

        focusTypeList.add(UserType.COMPLEX_TYPE);
        focusTypeList.add(OrgType.COMPLEX_TYPE);
        focusTypeList.add(RoleType.COMPLEX_TYPE);
        focusTypeList.add(ServiceType.COMPLEX_TYPE);

        return focusTypeList;
    }

    // TODO: move to schema component
    public static List<QName> createAbstractRoleTypeList() {
        List<QName> focusTypeList = new ArrayList<>();

        focusTypeList.add(AbstractRoleType.COMPLEX_TYPE);
        focusTypeList.add(OrgType.COMPLEX_TYPE);
        focusTypeList.add(RoleType.COMPLEX_TYPE);
        focusTypeList.add(ServiceType.COMPLEX_TYPE);

        return focusTypeList;
    }

    public static List<ObjectTypes> createAssignableTypesList() {
        List<ObjectTypes> focusTypeList = new ArrayList<>();

        focusTypeList.add(ObjectTypes.RESOURCE);
        focusTypeList.add(ObjectTypes.ORG);
        focusTypeList.add(ObjectTypes.ROLE);
        focusTypeList.add(ObjectTypes.SERVICE);

        return focusTypeList;
    }

    /**
     * Takes a collection of object types (classes) that may contain abstract types. Returns a collection
     * that only contain concrete types.
     * @param <O> common supertype for all the types in the collections
     *
     * TODO: move to schema component
     */
    public static <O extends ObjectType> List<QName> resolveObjectTypesToQNames(
            Collection<Class<? extends O>> types, PrismContext prismContext) {
        if (types == null) {
            return null;
        }
        List<QName> concreteTypes = new ArrayList<>(types.size());
        for (Class<? extends O> type : types) {
            if (type == null || type.equals(ObjectType.class)) {
                MiscUtil.addAllIfNotPresent(concreteTypes, WebComponentUtil.createObjectTypeList());
            } else if (type.equals(FocusType.class)) {
                MiscUtil.addAllIfNotPresent(concreteTypes, WebComponentUtil.createFocusTypeList());
            } else if (type.equals(AbstractRoleType.class)) {
                MiscUtil.addAllIfNotPresent(concreteTypes, WebComponentUtil.createAbstractRoleTypeList());
            } else {
                MiscUtil.addIfNotPresent(concreteTypes, WebComponentUtil.classToQName(prismContext, type));
            }
        }
        return concreteTypes;
    }

    public static <T extends Enum> IModel<String> createLocalizedModelForEnum(T value, Component comp) {
        String key = value != null ? value.getClass().getSimpleName() + "." + value.name() : "";
        return new StringResourceModel(key, comp, null);
    }

    public static <T extends Enum> IModel<List<T>> createReadonlyModelFromEnum(final Class<T> type) {
        return new AbstractReadOnlyModel<List<T>>() {

            @Override
            public List<T> getObject() {
                List<T> list = new ArrayList<>();
                Collections.addAll(list, type.getEnumConstants());

                return list;
            }
        };
    }

    // use for small enums only
    @NotNull
    public static <T extends Enum> IModel<List<T>> createReadonlyValueModelFromEnum(@NotNull Class<T> type,
            @NotNull Predicate<T> filter) {
        return new ReadOnlyValueModel<>(
                Arrays.stream(type.getEnumConstants()).filter(filter).collect(Collectors.toList()));
    }

    public static List<String> createTaskCategoryList() {
        List<String> categories = new ArrayList<>();

        // todo change to something better and add i18n
        // TaskManager manager = getTaskManager();
        // List<String> list = manager.getAllTaskCategories();
        // if (list != null) {
        // Collections.sort(list);
        // for (String item : list) {
        // if (item != TaskCategory.IMPORT_FROM_FILE && item !=
        // TaskCategory.WORKFLOW) {
        // categories.add(item);
        // }
        // }
        // }
        categories.add(TaskCategory.LIVE_SYNCHRONIZATION);
        categories.add(TaskCategory.RECONCILIATION);
        categories.add(TaskCategory.IMPORTING_ACCOUNTS);
        categories.add(TaskCategory.RECOMPUTATION);
        categories.add(TaskCategory.DEMO);
        // TODO: what about other categories?
        // categories.add(TaskCategory.ACCESS_CERTIFICATION);
        // categories.add(TaskCategory.BULK_ACTIONS);
        // categories.add(TaskCategory.CUSTOM);
        // categories.add(TaskCategory.EXECUTE_CHANGES);
        // categories.add(TaskCategory.IMPORT_FROM_FILE);
        // categories.add(TaskCategory.IMPORT_FROM_FILE);
        return categories;
    }

    public static IModel<String> createCategoryNameModel(final Component component,
            final IModel<String> categorySymbolModel) {
        return new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                return createStringResourceStatic(component,
                        "pageTasks.category." + categorySymbolModel.getObject()).getString();
            }
        };
    }

    public static ObjectReferenceType createObjectRef(String oid, String name, QName type) {
        ObjectReferenceType ort = new ObjectReferenceType();
        ort.setOid(oid);
        ort.setTargetName(createPolyFromOrigString(name));
        ort.setType(type);
        return ort;
    }

    // public static DropDownChoicePanel createActivationStatusPanel(String id,
    // final IModel<ActivationStatusType> model,
    // final Component component) {
    // return new DropDownChoicePanel(id, model,
    // WebMiscUtil.createReadonlyModelFromEnum(ActivationStatusType.class),
    // new IChoiceRenderer<ActivationStatusType>() {
    //
    // @Override
    // public Object getDisplayValue(ActivationStatusType object) {
    // return WebMiscUtil.createLocalizedModelForEnum(object,
    // component).getObject();
    // }
    //
    // @Override
    // public String getIdValue(ActivationStatusType object, int index) {
    // return Integer.toString(index);
    // }
    // }, true);
    // }

    public static <E extends Enum> DropDownChoicePanel createEnumPanel(Class clazz, String id,
            final IModel<E> model, final Component component) {
        return createEnumPanel(clazz, id, model, component, true);

    }

    public static <E extends Enum> DropDownChoicePanel createEnumPanel(Class clazz, String id,
            final IModel<E> model, final Component component, boolean allowNull) {
        return createEnumPanel(clazz, id, WebComponentUtil.createReadonlyModelFromEnum(clazz), model, component,
                allowNull);
    }

    public static <E extends Enum> DropDownChoicePanel<E> createEnumPanel(Class<E> clazz, String id,
            IModel<List<E>> choicesList, final IModel<E> model, final Component component, boolean allowNull) {
        return createEnumPanel(clazz, id, choicesList, model, component, allowNull, null);
    }

    public static <E extends Enum> DropDownChoicePanel<E> createEnumPanel(Class<E> clazz, String id,
            IModel<List<E>> choicesList, final IModel<E> model, final Component component, boolean allowNull,
            String nullValidDisplayValue) {
        return new DropDownChoicePanel<E>(id, model, choicesList, new IChoiceRenderer<E>() {

            private static final long serialVersionUID = 1L;

            @Override
            public E getObject(String id, IModel<? extends List<? extends E>> choices) {
                if (StringUtils.isBlank(id)) {
                    return null;
                }
                return choices.getObject().get(Integer.parseInt(id));
            }

            @Override
            public Object getDisplayValue(E object) {
                return WebComponentUtil.createLocalizedModelForEnum(object, component).getObject();
            }

            @Override
            public String getIdValue(E object, int index) {
                return Integer.toString(index);
            }
        }, allowNull) {

            private static final long serialVersionUID = 1L;

            @Override
            protected String getNullValidDisplayValue() {
                return nullValidDisplayValue != null && StringUtils.isNotEmpty(nullValidDisplayValue.trim())
                        ? nullValidDisplayValue
                        : super.getNullValidDisplayValue();
            }
        };
    }

    public static DropDownChoicePanel createEnumPanel(final PrismPropertyDefinition def, String id,
            final IModel model, final Component component) {
        // final Class clazz = model.getObject().getClass();
        final Object o = model.getObject();

        final IModel<List<DisplayableValue>> enumModelValues = new AbstractReadOnlyModel<List<DisplayableValue>>() {

            private static final long serialVersionUID = 1L;

            @Override
            public List<DisplayableValue> getObject() {
                return getDisplayableValues(def);
            }

        };

        return new DropDownChoicePanel(id, model, enumModelValues,
                new DisplayableValueChoiceRenderer(getDisplayableValues(def)), true);

        //      @Override
        //      public Object getObject(String id, IModel choices) {
        //         if (StringUtils.isBlank(id)) {
        //            return null;
        //         }
        //         return ((List) choices.getObject()).get(Integer.parseInt(id));
        //      }
        //
        //      @Override
        //      public Object getDisplayValue(Object object) {
        //         if (object instanceof DisplayableValue) {
        //            return ((DisplayableValue) object).getLabel();
        //         }
        //         for (DisplayableValue v : enumModelValues.getObject()) {
        //            if (object.equals(v.getValue())) {
        //               return v.getLabel();
        //            }
        //         }
        //         return object;
        //
        //      }
        //
        //      @Override
        //      public String getIdValue(Object object, int index) {
        //            if (object instanceof String && enumModelValues != null && enumModelValues.getObject() != null) {
        //                List<DisplayableValue> enumValues = enumModelValues.getObject();
        //                for (DisplayableValue v : enumValues) {
        //                    if (object.equals(v.getValue())) {
        //                        return String.valueOf(enumValues.indexOf(v));
        //                    }
        //                }
        //            }
        //            return String.valueOf(index);
        //      }
    }

    public static <IW extends ItemWrapper, C extends Containerable> PropertyModel createPrismPropertySingleValueModel(
            IModel<ContainerValueWrapper<C>> containerModel, QName attributeName) {
        //todo should be refactored: wrap with some new  model
        PropertyModel<List<IW>> propertiesModel = new PropertyModel<>(containerModel, "properties");
        List<IW> propertiesList = propertiesModel.getObject();
        for (final IW property : propertiesList) {
            if (property.getName().equals(attributeName)) {
                List<ValueWrapper> valuesList = property.getValues();
                if (valuesList.size() == 1) {
                    return new PropertyModel<>(valuesList.get(0).getValue(), "value");
                }

            }
        }
        return null;
    }

    private static List<DisplayableValue> getDisplayableValues(PrismPropertyDefinition def) {
        List<DisplayableValue> values = null;
        if (def.getAllowedValues() != null) {
            values = new ArrayList<>(def.getAllowedValues().size());
            for (Object v : def.getAllowedValues()) {
                if (v instanceof DisplayableValue) {
                    values.add(((DisplayableValue) v));
                }
            }
        }
        return values;
    }

    public static <T> TextField<T> createAjaxTextField(String id, IModel<T> model) {
        TextField<T> textField = new TextField<>(id, model);
        textField.add(new EmptyOnBlurAjaxFormUpdatingBehaviour());
        return textField;
    }

    public static CheckBox createAjaxCheckBox(String id, IModel<Boolean> model) {
        CheckBox checkBox = new CheckBox(id, model);
        checkBox.add(new EmptyOnChangeAjaxFormUpdatingBehavior());
        return checkBox;
    }

    public static String getName(ObjectType object) {
        if (object == null) {
            return null;
        }

        return getName(object.asPrismObject());
    }

    public static String getEffectiveName(ObjectType object, QName propertyName) {
        if (object == null) {
            return null;
        }

        return getEffectiveName(object.asPrismObject(), propertyName);
    }

    public static <O extends ObjectType> String getEffectiveName(PrismObject<O> object, QName propertyName) {
        if (object == null) {
            return null;
        }

        PrismProperty prop = object.findProperty(propertyName);

        if (prop != null) {
            Object realValue = prop.getRealValue();
            if (prop.getDefinition().getTypeName().equals(DOMUtil.XSD_STRING)) {
                return (String) realValue;
            } else if (realValue instanceof PolyString) {
                return WebComponentUtil.getOrigStringFromPoly((PolyString) realValue);
            }
        }

        PolyString name = getValue(object, ObjectType.F_NAME, PolyString.class);

        return name != null ? name.getOrig() : null;
    }

    public static <O extends ObjectType> String getName(ObjectReferenceType ref, PageBase pageBase,
            String operation) {
        String name = getName(ref);
        if (StringUtils.isEmpty(name) || name.equals(ref.getOid())) {
            String oid = ref.getOid();
            Collection<SelectorOptions<GetOperationOptions>> options = SelectorOptions
                    .createCollection(GetOperationOptions.createNoFetch());
            Class<O> type = (Class<O>) ObjectType.class;
            PrismObject<O> object = WebModelServiceUtils.loadObject(type, oid, pageBase,
                    pageBase.createSimpleTask(operation), new OperationResult(operation));
            if (object != null) {
                name = object.getName().getOrig();
            }
        }
        return name;
    }

    public static <O extends ObjectType> String getDisplayNameOrName(ObjectReferenceType ref, PageBase pageBase,
            String operation) {
        String name = getName(ref);
        if (StringUtils.isEmpty(name) || name.equals(ref.getOid())) {
            String oid = ref.getOid();
            Collection<SelectorOptions<GetOperationOptions>> options = SelectorOptions
                    .createCollection(GetOperationOptions.createNoFetch());
            Class<O> type = ref.getType() != null
                    ? (Class<O>) qnameToClass(pageBase.getPrismContext(), ref.getType())
                    : (Class<O>) ObjectType.class;
            PrismObject<O> object = WebModelServiceUtils.loadObject(type, oid, pageBase,
                    pageBase.createSimpleTask(operation), new OperationResult(operation));
            if (object != null) {
                name = getDisplayNameOrName(object);
            }
        }
        return name;
    }

    public static <O extends ObjectType> String getEffectiveName(ObjectReferenceType ref, QName propertyName,
            PageBase pageBase, String operation) {
        PrismObject<O> object = WebModelServiceUtils.loadObject(ref, pageBase, pageBase.createSimpleTask(operation),
                new OperationResult(operation));

        if (object == null) {
            return "Not Found";
        }

        return getEffectiveName(object, propertyName);

    }

    public static String getName(ObjectReferenceType ref) {
        if (ref == null) {
            return null;
        }
        if (ref.getTargetName() != null) {
            return getOrigStringFromPoly(ref.getTargetName());
        }
        if (ref.asReferenceValue().getObject() != null) {
            return getName(ref.asReferenceValue().getObject());
        }
        return ref.getOid();
    }

    public static String getName(PrismObject object) {
        if (object == null) {
            return null;
        }
        PolyString name = getValue(object, ObjectType.F_NAME, PolyString.class);

        return name != null ? name.getOrig() : null;
    }

    public static <C extends Containerable> String getDisplayName(PrismContainerValue<C> prismContainerValue) {
        if (prismContainerValue == null) {
            return "ContainerPanel.containerProperties";
        }

        if (prismContainerValue.canRepresent(AssignmentType.class)) {
            AssignmentType assignmentType = (AssignmentType) prismContainerValue.asContainerable();
            if (assignmentType.getTargetRef() != null) {
                ObjectReferenceType assignemntTargetRef = assignmentType.getTargetRef();
                return getName(assignemntTargetRef) + " - "
                        + normalizeRelation(assignemntTargetRef.getRelation()).getLocalPart();
            } else {
                return "AssignmentTypeDetailsPanel.containerTitle";
            }
        }

        if (prismContainerValue.canRepresent(ExclusionPolicyConstraintType.class)) {
            ExclusionPolicyConstraintType exclusionConstraint = (ExclusionPolicyConstraintType) prismContainerValue
                    .asContainerable();
            String displayName = (exclusionConstraint.getName() != null ? exclusionConstraint.getName()
                    : exclusionConstraint.asPrismContainerValue().getParent().getPath().last()) + " - "
                    + StringUtils.defaultIfEmpty(getName(exclusionConstraint.getTargetRef()), "");
            return StringUtils.isNotEmpty(displayName) ? displayName : "Not defined exclusion name";
        }
        if (prismContainerValue.canRepresent(AbstractPolicyConstraintType.class)) {
            AbstractPolicyConstraintType constraint = (AbstractPolicyConstraintType) prismContainerValue
                    .asContainerable();
            String displayName = (StringUtils.isEmpty(constraint.getName())
                    ? (constraint.asPrismContainerValue().getParent().getPath().last())
                    : constraint.getName())
                    + (StringUtils.isEmpty(constraint.getDescription()) ? ""
                            : (" - " + constraint.getDescription()));
            return displayName;
        }
        Class<C> cvalClass = prismContainerValue.getCompileTimeClass();
        if (cvalClass != null) {
            return cvalClass.getSimpleName() + ".details";
        }
        return "ContainerPanel.containerProperties";
    }

    public static String getDisplayNameOrName(PrismObject object) {
        if (object == null) {
            return null;
        }

        String displayName = getDisplayName(object);
        return displayName != null ? displayName : getName(object);
    }

    public static String getDisplayNameOrName(ObjectReferenceType ref) {
        if (ref == null) {
            return null;
        }
        String displayName = getDisplayName(ref);
        return displayName != null ? displayName : getName(ref);
    }

    // <display-name> (<name>) OR simply <name> if there's no display name
    private static String getDisplayNameAndName(ObjectReferenceType ref) {
        if (ref == null) {
            return null;
        }
        String displayName = getDisplayName(ref);
        String name = getName(ref);
        return displayName != null ? displayName + " (" + name + ")" : name;
    }

    public static String getDisplayName(ObjectReferenceType ref) {
        return PolyString.getOrig(ObjectTypeUtil.getDisplayName(ref));
    }

    public static String getDisplayName(PrismObject object) {
        return PolyString.getOrig(ObjectTypeUtil.getDisplayName(object));
    }

    public static String getIdentification(ObjectType object) {
        if (object == null) {
            return null;
        }
        return getName(object.asPrismObject()) + " (" + object.getOid() + ")";
    }

    public static PolyStringType createPolyFromOrigString(String str) {
        if (str == null) {
            return null;
        }

        PolyStringType poly = new PolyStringType();
        poly.setOrig(str);

        return poly;
    }

    public static String getOrigStringFromPoly(PolyString str) {
        return str != null ? str.getOrig() : null;
    }

    public static String getOrigStringFromPoly(PolyStringType str) {
        return str != null ? str.getOrig() : null;
    }

    public static <T> T getValue(PrismContainerValue object, QName propertyName, Class<T> type) {
        if (object == null) {
            return null;
        }

        PrismProperty property = object.findProperty(propertyName);
        if (property == null || property.isEmpty()) {
            return null;
        }

        return (T) property.getRealValue(type);
    }

    public static <T> T getContainerValue(PrismContainerValue object, QName containerName, Class<T> type) {
        if (object == null) {
            return null;
        }

        PrismContainer container = object.findContainer(containerName);
        if (container == null || container.isEmpty()) {
            return null;
        }

        PrismContainerValue containerValue = container.getValue();

        if (containerValue == null || containerValue.isEmpty()) {
            return null;
        }

        return (T) containerValue.getValue();
    }

    public static <T> T getValue(PrismContainer object, QName propertyName, Class<T> type) {
        if (object == null) {
            return null;
        }

        return getValue(object.getValue(), propertyName, type);
    }

    public static Locale getLocaleFromString(String localeString) {
        if (localeString == null) {
            return null;
        }
        localeString = localeString.trim();
        if (localeString.toLowerCase().equals("default")) {
            return Locale.getDefault();
        }

        // Extract language
        int languageIndex = localeString.indexOf('_');
        String language = null;
        if (languageIndex == -1) {
            // No further "_" so is "{language}" only
            return new Locale(localeString, "");
        } else {
            language = localeString.substring(0, languageIndex);
        }

        // Extract country
        int countryIndex = localeString.indexOf('_', languageIndex + 1);
        String country = null;
        if (countryIndex == -1) {
            // No further "_" so is "{language}_{country}"
            country = localeString.substring(languageIndex + 1);
            return new Locale(language, country);
        } else {
            // Assume all remaining is the variant so is
            // "{language}_{country}_{variant}"
            country = localeString.substring(languageIndex + 1, countryIndex);
            String variant = localeString.substring(countryIndex + 1);
            return new Locale(language, country, variant);
        }
    }

    public static void encryptCredentials(ObjectDelta delta, boolean encrypt, MidPointApplication app) {
        if (delta == null || delta.isEmpty()) {
            return;
        }

        PropertyDelta propertyDelta = delta.findPropertyDelta(new ItemPath(SchemaConstantsGenerated.C_CREDENTIALS,
                CredentialsType.F_PASSWORD, PasswordType.F_VALUE));
        if (propertyDelta == null) {
            return;
        }

        Collection<PrismPropertyValue<ProtectedStringType>> values = propertyDelta
                .getValues(ProtectedStringType.class);
        for (PrismPropertyValue<ProtectedStringType> value : values) {
            ProtectedStringType string = value.getValue();
            encryptProtectedString(string, encrypt, app);
        }
    }

    public static void encryptCredentials(PrismObject object, boolean encrypt, MidPointApplication app) {
        PrismContainer password = object
                .findContainer(new ItemPath(SchemaConstantsGenerated.C_CREDENTIALS, CredentialsType.F_PASSWORD));
        if (password == null) {
            return;
        }
        PrismProperty protectedStringProperty = password.findProperty(PasswordType.F_VALUE);
        if (protectedStringProperty == null
                || protectedStringProperty.getRealValue(ProtectedStringType.class) == null) {
            return;
        }

        ProtectedStringType string = (ProtectedStringType) protectedStringProperty
                .getRealValue(ProtectedStringType.class);

        encryptProtectedString(string, encrypt, app);
    }

    public static void encryptProtectedString(ProtectedStringType string, boolean encrypt,
            MidPointApplication app) {
        if (string == null) {
            return;
        }
        Protector protector = app.getProtector();
        try {
            if (encrypt) {
                if (StringUtils.isEmpty(string.getClearValue())) {
                    return;
                }
                protector.encrypt(string);
            } else {
                if (string.getEncryptedDataType() == null) {
                    return;
                }
                protector.decrypt(string);
            }
        } catch (EncryptionException ex) {
            LoggingUtils.logUnexpectedException(LOGGER, "Couldn't encrypt protected string", ex);
        } catch (SchemaException e) {
            LoggingUtils.logUnexpectedException(LOGGER, "Couldn't encrypt/decrypt protected string", e);
        }
    }

    public static <T extends Selectable> List<T> getSelectedData(Table table) {
        DataTable dataTable = table.getDataTable();
        BaseSortableDataProvider<T> provider = (BaseSortableDataProvider<T>) dataTable.getDataProvider();

        List<T> selected = new ArrayList<>();
        for (T bean : provider.getAvailableData()) {
            if (bean.isSelected()) {
                selected.add(bean);
            }
        }

        return selected;
    }

    public static void clearProviderCache(IDataProvider provider) {
        if (provider == null) {
            return;
        }
        if (provider instanceof BaseSortableDataProvider) {
            ((BaseSortableDataProvider) provider).clearCache();
        }
        if (provider instanceof SelectableBeanObjectDataProvider) {
            ((SelectableBeanObjectDataProvider) provider).clearSelectedObjects();
        }
    }

    public static Collection<ObjectDelta<? extends ObjectType>> createDeltaCollection(
            ObjectDelta<? extends ObjectType>... deltas) {
        Collection<ObjectDelta<? extends ObjectType>> collection = new ArrayList<>();
        for (ObjectDelta delta : deltas) {
            collection.add(delta);
        }

        return collection;
    }

    public static boolean showResultInPage(OperationResult result) {
        if (result == null) {
            return false;
        }

        return !result.isSuccess() && !result.isHandledError() && !result.isInProgress();
    }

    public static String formatDate(XMLGregorianCalendar calendar) {
        if (calendar == null) {
            return null;
        }

        return formatDate(XmlTypeConverter.toDate(calendar));
    }

    public static String formatDate(Date date) {
        return formatDate(null, date);
    }

    public static String formatDate(String format, Date date) {
        if (date == null) {
            return null;
        }

        if (StringUtils.isEmpty(format)) {
            format = "EEEE, d. MMM yyyy HH:mm:ss";
        }
        Locale locale = Session.get().getLocale();
        if (locale == null) {
            locale = Locale.US;
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat(format, locale);
        return dateFormat.format(date);
    }

    public static String getLocalizedDatePattern(String style) {
        return DateTimeFormat.patternForStyle(style, getCurrentLocale());
    }

    public static Locale getCurrentLocale() {
        Locale locale = Session.get().getLocale();
        if (locale == null) {
            locale = Locale.getDefault();
        }
        return locale;
    }

    public static String getLocalizedDate(XMLGregorianCalendar date, String style) {
        return getLocalizedDate(XmlTypeConverter.toDate(date), style);
    }

    public static String getLocalizedDate(Date date, String style) {
        if (date == null) {
            return null;
        }
        PatternDateConverter converter = new PatternDateConverter(getLocalizedDatePattern(style), true);
        return converter.convertToString(date, WebComponentUtil.getCurrentLocale());
    }

    public static boolean isActivationEnabled(PrismObject object) {
        Validate.notNull(object);

        PrismContainer activation = object.findContainer(UserType.F_ACTIVATION); // this
        // is
        // equal
        // to
        // account
        // activation...
        if (activation == null) {
            return false;
        }

        ActivationStatusType status = (ActivationStatusType) activation
                .getPropertyRealValue(ActivationType.F_ADMINISTRATIVE_STATUS, ActivationStatusType.class);
        if (status == null) {
            return false;
        }

        // todo imrove with activation dates...
        return ActivationStatusType.ENABLED.equals(status);
    }

    public static boolean isSuccessOrHandledError(OperationResult result) {
        if (result == null) {
            return false;
        }

        return result.isSuccess() || result.isHandledError();
    }

    public static boolean isSuccessOrHandledError(OperationResultType resultType) {
        if (resultType == null) {
            return false;
        }
        return resultType.getStatus() == OperationResultStatusType.SUCCESS
                || resultType.getStatus() == OperationResultStatusType.HANDLED_ERROR;
    }

    public static boolean isSuccessOrHandledErrorOrWarning(OperationResult result) {
        if (result == null) {
            return false;
        }

        return result.isSuccess() || result.isHandledError() || result.isWarning();
    }

    public static boolean isSuccessOrHandledErrorOrInProgress(OperationResult result) {
        if (result == null) {
            return false;
        }

        return result.isSuccess() || result.isHandledError() || result.isInProgress();
    }

    public static <T extends ObjectType> String createDefaultIcon(T object) {
        return createDefaultIcon(object.asPrismObject());
    }

    public static <T extends ObjectType> String createDefaultIcon(PrismObject<T> object) {
        Class<T> type = object.getCompileTimeClass();
        if (type.equals(UserType.class)) {
            return createUserIcon((PrismObject<UserType>) object);
        } else if (RoleType.class.equals(type)) {
            return createRoleIcon((PrismObject<RoleType>) object);
        } else if (OrgType.class.equals(type)) {
            return createOrgIcon((PrismObject<OrgType>) object);
        } else if (ServiceType.class.equals(type)) {
            return createServiceIcon((PrismObject<ServiceType>) object);
        } else if (type.equals(TaskType.class)) {
            return createTaskIcon((PrismObject<TaskType>) object);
        } else if (type.equals(ResourceType.class)) {
            return createResourceIcon((PrismObject<ResourceType>) object);
        }

        return "";
    }

    // TODO reconcile with ObjectTypeGuiDescriptor
    public static <T extends ObjectType> String createDefaultColoredIcon(QName objectType) {
        if (objectType == null) {
            return "";
        } else if (QNameUtil.match(UserType.COMPLEX_TYPE, objectType)
                || QNameUtil.match(PersonaConstructionType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_USER_ICON_COLORED;
        } else if (QNameUtil.match(RoleType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_ROLE_ICON_COLORED;
        } else if (QNameUtil.match(OrgType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_ORG_ICON_COLORED;
        } else if (QNameUtil.match(ServiceType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_SERVICE_ICON_COLORED;
        } else if (QNameUtil.match(TaskType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_TASK_ICON_COLORED;
        } else if (QNameUtil.match(ResourceType.COMPLEX_TYPE, objectType)
                || QNameUtil.match(ConstructionType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_RESOURCE_ICON_COLORED;
        } else if (QNameUtil.match(AccessCertificationCampaignType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_CERT_CAMPAIGN_ICON_COLORED;
        } else if (QNameUtil.match(AccessCertificationDefinitionType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_CERT_DEF_ICON_COLORED;
        } else if (QNameUtil.match(WorkItemType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_WORK_ITEM_ICON_COLORED;
        } else if (QNameUtil.match(ShadowType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_SHADOW_ICON_COLORED;
        } else if (QNameUtil.match(PolicyRuleType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_POLICY_RULES_ICON_COLORED;
        } else {
            return "";
        }
    }

    // TODO reconcile with ObjectTypeGuiDescriptor
    public static <T extends ObjectType> String createDefaultBlackIcon(QName objectType) {
        if (objectType == null) {
            return "";
        } else if (QNameUtil.match(UserType.COMPLEX_TYPE, objectType)
                || QNameUtil.match(PersonaConstructionType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_USER_ICON;
        } else if (QNameUtil.match(RoleType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_ROLE_ICON;
        } else if (QNameUtil.match(OrgType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_ORG_ICON;
        } else if (QNameUtil.match(ServiceType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_SERVICE_ICON;
        } else if (QNameUtil.match(TaskType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_TASK_ICON;
        } else if (QNameUtil.match(ResourceType.COMPLEX_TYPE, objectType)
                || QNameUtil.match(ConstructionType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_RESOURCE_ICON;
        } else if (QNameUtil.match(AccessCertificationCampaignType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_CERT_CAMPAIGN_ICON;
        } else if (QNameUtil.match(AccessCertificationDefinitionType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_CERT_DEF_ICON;
        } else if (QNameUtil.match(WorkItemType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_WORK_ITEM_ICON;
        } else if (QNameUtil.match(ShadowType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_SHADOW_ICON;
        } else if (QNameUtil.match(PolicyRuleType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_POLICY_RULES_ICON;
        } else {
            return "";
        }
    }

    public static <T extends ObjectType> String getBoxCssClasses(QName objectType) {
        if (QNameUtil.match(UserType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_USER_BOX_CSS_CLASSES;
        } else if (QNameUtil.match(RoleType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_ROLE_BOX_CSS_CLASSES;
        } else if (QNameUtil.match(OrgType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_ORG_BOX_CSS_CLASSES;
        } else if (QNameUtil.match(ServiceType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_SERVICE_BOX_CSS_CLASSES;
        } else if (QNameUtil.match(TaskType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_TASK_BOX_CSS_CLASSES;
        } else if (QNameUtil.match(ResourceType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_RESOURCE_BOX_CSS_CLASSES;
        } else {
            return "";
        }
    }

    public static <T extends ObjectType> String getBoxThinCssClasses(QName objectType) {
        if (QNameUtil.match(UserType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_USER_BOX_THIN_CSS_CLASSES;
        } else if (QNameUtil.match(RoleType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_ROLE_BOX_THIN_CSS_CLASSES;
        } else if (QNameUtil.match(OrgType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_ORG_BOX_THIN_CSS_CLASSES;
        } else if (QNameUtil.match(ServiceType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_SERVICE_BOX_THIN_CSS_CLASSES;
        } else if (QNameUtil.match(TaskType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_TASK_BOX_THIN_CSS_CLASSES;
        } else if (QNameUtil.match(ResourceType.COMPLEX_TYPE, objectType)) {
            return GuiStyleConstants.CLASS_OBJECT_RESOURCE_BOX_THIN_CSS_CLASSES;
        } else {
            return "";
        }
    }

    public static String createUserIcon(PrismObject<UserType> object) {
        UserType user = object.asObjectable();

        // if user has superuser role assigned, it's superuser
        boolean isEndUser = false;
        for (AssignmentType assignment : user.getAssignment()) {
            ObjectReferenceType targetRef = assignment.getTargetRef();
            if (targetRef == null) {
                continue;
            }
            if (StringUtils.equals(targetRef.getOid(), SystemObjectsType.ROLE_SUPERUSER.value())) {
                return GuiStyleConstants.CLASS_OBJECT_USER_ICON + " "
                        + GuiStyleConstants.CLASS_ICON_STYLE_PRIVILEGED;
            }
            if (StringUtils.equals(targetRef.getOid(), SystemObjectsType.ROLE_END_USER.value())) {
                isEndUser = true;
            }
        }

        boolean isManager = false;
        for (ObjectReferenceType parentOrgRef : user.getParentOrgRef()) {
            if (ObjectTypeUtil.isManagerRelation(parentOrgRef.getRelation())) {
                isManager = true;
                break;
            }
        }

        String additionalStyle = getIconEnabledDisabled(object);
        if (additionalStyle == null) {
            // Set manager and end-user icon only as a last resort. All other
            // colors have priority.
            if (isManager) {
                additionalStyle = GuiStyleConstants.CLASS_ICON_STYLE_MANAGER;
            } else if (isEndUser) {
                additionalStyle = GuiStyleConstants.CLASS_ICON_STYLE_END_USER;
            } else {
                additionalStyle = GuiStyleConstants.CLASS_ICON_STYLE_NORMAL;
            }
        }
        return GuiStyleConstants.CLASS_OBJECT_USER_ICON + " " + additionalStyle;
    }

    public static String createRoleIcon(PrismObject<RoleType> object) {
        for (AuthorizationType authorization : object.asObjectable().getAuthorization()) {
            if (authorization.getAction().contains(AuthorizationConstants.AUTZ_ALL_URL)) {
                return GuiStyleConstants.CLASS_OBJECT_ROLE_ICON + " "
                        + GuiStyleConstants.CLASS_ICON_STYLE_PRIVILEGED;
            }
        }

        return getIconEnabledDisabled(object, GuiStyleConstants.CLASS_OBJECT_ROLE_ICON);
    }

    public static String createOrgIcon(PrismObject<OrgType> object) {
        return getIconEnabledDisabled(object, GuiStyleConstants.CLASS_OBJECT_ORG_ICON);
    }

    public static String createServiceIcon(PrismObject<ServiceType> object) {
        return getIconEnabledDisabled(object, GuiStyleConstants.CLASS_OBJECT_SERVICE_ICON);
    }

    private static <F extends FocusType> String getIconEnabledDisabled(PrismObject<F> object, String baseIcon) {
        String additionalStyle = getIconEnabledDisabled(object);
        if (additionalStyle == null) {
            return baseIcon + " " + GuiStyleConstants.CLASS_ICON_STYLE_NORMAL;
        } else {
            return baseIcon + " " + additionalStyle;
        }
    }

    private static <F extends FocusType> String getIconEnabledDisabled(PrismObject<F> object) {
        ActivationType activation = object.asObjectable().getActivation();
        if (activation != null) {
            if (ActivationStatusType.DISABLED.equals(activation.getEffectiveStatus())) {
                return GuiStyleConstants.CLASS_ICON_STYLE_DISABLED;
            } else if (ActivationStatusType.ARCHIVED.equals(activation.getEffectiveStatus())) {
                return GuiStyleConstants.CLASS_ICON_STYLE_ARCHIVED;
            }
        }

        return null;
    }

    public static String createResourceIcon(PrismObject<ResourceType> object) {
        OperationalStateType operationalState = object.asObjectable().getOperationalState();
        if (operationalState != null) {
            AvailabilityStatusType lastAvailabilityStatus = operationalState.getLastAvailabilityStatus();
            if (lastAvailabilityStatus == AvailabilityStatusType.UP) {
                return GuiStyleConstants.CLASS_OBJECT_RESOURCE_ICON + " " + GuiStyleConstants.CLASS_ICON_STYLE_UP;
            }
            if (lastAvailabilityStatus == AvailabilityStatusType.DOWN) {
                return GuiStyleConstants.CLASS_OBJECT_RESOURCE_ICON + " " + GuiStyleConstants.CLASS_ICON_STYLE_DOWN;
            }

            if (lastAvailabilityStatus == AvailabilityStatusType.BROKEN) {
                return GuiStyleConstants.CLASS_OBJECT_RESOURCE_ICON + " "
                        + GuiStyleConstants.CLASS_ICON_STYLE_BROKEN;
            }
        }
        return GuiStyleConstants.CLASS_OBJECT_RESOURCE_ICON + " " + GuiStyleConstants.CLASS_ICON_STYLE_NORMAL;
    }

    public static String createTaskIcon(PrismObject<TaskType> object) {
        return GuiStyleConstants.CLASS_OBJECT_TASK_ICON + " " + GuiStyleConstants.CLASS_ICON_STYLE_NORMAL;
    }

    public static String createShadowIcon(PrismObject<ShadowType> object) {
        ShadowType shadow = object.asObjectable();

        if (ShadowUtil.isProtected(object)) {
            return GuiStyleConstants.CLASS_SHADOW_ICON_PROTECTED;
        }

        ShadowKindType kind = shadow.getKind();
        if (kind == null) {
            return GuiStyleConstants.CLASS_SHADOW_ICON_UNKNOWN;
        }

        switch (kind) {
        case ACCOUNT:
            return GuiStyleConstants.CLASS_SHADOW_ICON_ACCOUNT;
        case GENERIC:
            return GuiStyleConstants.CLASS_SHADOW_ICON_GENERIC;
        case ENTITLEMENT:
            return GuiStyleConstants.CLASS_SHADOW_ICON_ENTITLEMENT;

        }

        return GuiStyleConstants.CLASS_SHADOW_ICON_UNKNOWN;
    }

    public static String createUserIconTitle(PrismObject<UserType> object) {
        UserType user = object.asObjectable();

        // if user has superuser role assigned, it's superuser
        for (AssignmentType assignment : user.getAssignment()) {
            ObjectReferenceType targetRef = assignment.getTargetRef();
            if (targetRef == null) {
                continue;
            }
            if (StringUtils.equals(targetRef.getOid(), SystemObjectsType.ROLE_SUPERUSER.value())) {
                return "user.superuser";
            }
        }

        ActivationType activation = user.getActivation();
        if (activation != null) {
            if (ActivationStatusType.DISABLED.equals(activation.getEffectiveStatus())) {
                return "ActivationStatusType.DISABLED";
            } else if (ActivationStatusType.ARCHIVED.equals(activation.getEffectiveStatus())) {
                return "ActivationStatusType.ARCHIVED";
            }
        }

        return null;
    }

    public static String createErrorIcon(OperationResult result) {
        OperationResultStatus status = result.getStatus();
        OperationResultStatusPresentationProperties icon = OperationResultStatusPresentationProperties
                .parseOperationalResultStatus(status);
        return icon.getIcon() + " fa-lg";
    }

    public static double getSystemLoad() {
        com.sun.management.OperatingSystemMXBean operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory
                .getOperatingSystemMXBean();
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        int availableProcessors = operatingSystemMXBean.getAvailableProcessors();
        long prevUpTime = runtimeMXBean.getUptime();
        long prevProcessCpuTime = operatingSystemMXBean.getProcessCpuTime();

        try {
            Thread.sleep(150);
        } catch (Exception ignored) {
            // ignored
        }

        operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory
                .getOperatingSystemMXBean();
        long upTime = runtimeMXBean.getUptime();
        long processCpuTime = operatingSystemMXBean.getProcessCpuTime();
        long elapsedCpu = processCpuTime - prevProcessCpuTime;
        long elapsedTime = upTime - prevUpTime;

        double cpuUsage = Math.min(99F, elapsedCpu / (elapsedTime * 10000F * availableProcessors));

        return cpuUsage;
    }

    public static double getMaxRam() {
        int MB = 1024 * 1024;

        MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
        long maxHeap = mBean.getHeapMemoryUsage().getMax();
        long maxNonHeap = mBean.getNonHeapMemoryUsage().getMax();

        return (maxHeap + maxNonHeap) / MB;
    }

    public static double getRamUsage() {
        int MB = 1024 * 1024;

        MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
        long usedHead = mBean.getHeapMemoryUsage().getUsed();
        long usedNonHeap = mBean.getNonHeapMemoryUsage().getUsed();

        return (usedHead + usedNonHeap) / MB;
    }

    /**
     * Checks table if has any selected rows ({@link Selectable} interface
     * dtos), adds "single" parameter to selected items if it's not null. If
     * table has no selected rows warn message is added to feedback panel, and
     * feedback is refreshed through {@link AjaxRequestTarget}
     *
     * @param target
     * @param single
     *            this parameter is used for row actions when action must be
     *            done only on chosen row.
     * @param table
     * @param page
     * @param nothingWarnMessage
     * @param <T>
     * @return
     */
    public static <T extends Selectable> List<T> isAnythingSelected(AjaxRequestTarget target, T single, Table table,
            PageBase page, String nothingWarnMessage) {
        List<T> selected;
        if (single != null) {
            selected = new ArrayList<>();
            selected.add(single);
        } else {
            selected = WebComponentUtil.getSelectedData(table);
            if (selected.isEmpty()) {
                page.warn(page.getString(nothingWarnMessage));
                target.add(page.getFeedbackPanel());
            }
        }

        return selected;
    }

    public static void refreshFeedbacks(MarkupContainer component, final AjaxRequestTarget target) {
        component.visitChildren(IFeedback.class, new IVisitor<Component, Void>() {

            @Override
            public void component(final Component component, final IVisit<Void> visit) {
                target.add(component);
            }
        });
    }

    /*
     * Methods used for providing prismContext into various objects.
     */
    public static void revive(LoadableModel<?> loadableModel, PrismContext prismContext) throws SchemaException {
        if (loadableModel != null) {
            loadableModel.revive(prismContext);
        }
    }

    public static void revive(IModel<?> model, PrismContext prismContext) throws SchemaException {
        if (model != null && model.getObject() != null) {
            reviveObject(model.getObject(), prismContext);
        }
    }

    public static void reviveObject(Object object, PrismContext prismContext) throws SchemaException {
        if (object == null) {
            return;
        }
        if (object instanceof Collection) {
            for (Object item : (Collection) object) {
                reviveObject(item, prismContext);
            }
        } else if (object instanceof Revivable) {
            ((Revivable) object).revive(prismContext);
        }
    }

    // useful for components other than those inheriting from PageBase
    public static PrismContext getPrismContext(Component component) {
        return ((MidPointApplication) component.getApplication()).getPrismContext();
    }

    public static void reviveIfNeeded(ObjectType objectType, Component component) {
        if (objectType != null && objectType.asPrismObject().getPrismContext() == null) {
            try {
                objectType.asPrismObject().revive(getPrismContext(component));
            } catch (SchemaException e) {
                throw new SystemException("Couldn't revive " + objectType + " because of schema exception", e);
            }
        }
    }

    public static List<String> getChannelList() {
        List<String> channels = new ArrayList<>();

        for (Channel channel : Channel.values()) {
            channels.add(channel.getChannel());
        }

        return channels;
    }

    public static List<QName> getMatchingRuleList() {
        List<QName> list = new ArrayList<>();

        list.add(DefaultMatchingRule.NAME);
        list.add(StringIgnoreCaseMatchingRule.NAME);
        list.add(PolyStringStrictMatchingRule.NAME);
        list.add(PolyStringOrigMatchingRule.NAME);
        list.add(PolyStringNormMatchingRule.NAME);
        list.add(DistinguishedNameMatchingRule.NAME);
        list.add(ExchangeEmailAddressesMatchingRule.NAME);
        list.add(UuidMatchingRule.NAME);
        list.add(XmlMatchingRule.NAME);

        return list;
    }

    public static boolean isObjectOrgManager(PrismObject<? extends ObjectType> object) {
        if (object == null || object.asObjectable() == null) {
            return false;
        }

        ObjectType objectType = object.asObjectable();
        List<ObjectReferenceType> parentOrgRefs = objectType.getParentOrgRef();

        for (ObjectReferenceType ref : parentOrgRefs) {
            if (ObjectTypeUtil.isManagerRelation(ref.getRelation())) {
                return true;
            }
        }

        return false;
    }

    public static String createHumanReadableByteCount(long bytes) {
        int unit = 1024;
        if (bytes < unit)
            return bytes + "B";
        int exp = (int) (Math.log(bytes) / Math.log(unit));
        char pre = "KMGTPE".charAt(exp - 1);
        return String.format("%.1f%sB", bytes / Math.pow(unit, exp), pre);
    }

    public static void setCurrentPage(Table table, ObjectPaging paging) {
        if (table == null) {
            return;
        }

        if (paging == null) {
            table.getDataTable().setCurrentPage(0);
            return;
        }

        long itemsPerPage = table.getDataTable().getItemsPerPage();
        long page = ((paging.getOffset() + itemsPerPage) / itemsPerPage) - 1;
        if (page < 0) {
            page = 0;
        }

        table.getDataTable().setCurrentPage(page);
    }

    public static PageBase getPageBase(Component component) {
        Page page = component.getPage();
        if (page instanceof PageBase) {
            return (PageBase) page;
        } else if (page instanceof PageDialog) {
            return ((PageDialog) page).getPageBase();
        } else {
            throw new IllegalStateException("Couldn't determine page base for " + page);
        }
    }

    public static <T extends Component> T theSameForPage(T object, PageReference containingPageReference) {
        Page containingPage = containingPageReference.getPage();
        if (containingPage == null) {
            return object;
        }
        String path = object.getPageRelativePath();
        T retval = (T) containingPage.get(path);
        if (retval == null) {
            return object;
            // throw new IllegalStateException("There is no component like " +
            // object + " (path '" + path + "') on " + containingPage);
        }
        return retval;
    }

    public static String debugHandler(IRequestHandler handler) {
        if (handler == null) {
            return null;
        }
        if (handler instanceof RenderPageRequestHandler) {
            return "RenderPageRequestHandler(" + ((RenderPageRequestHandler) handler).getPageClass().getName()
                    + ")";
        } else {
            return handler.toString();
        }
    }

    public static ItemPath joinPath(ItemPath path, ItemPath deltaPath) {
        List<ItemPathSegment> newPath = new ArrayList<>();

        ItemPathSegment firstDeltaSegment = deltaPath != null ? deltaPath.first() : null;
        if (path != null) {
            for (ItemPathSegment seg : path.getSegments()) {
                if (seg.equivalent(firstDeltaSegment)) {
                    break;
                }
                newPath.add(seg);
            }
        }
        if (deltaPath != null) {
            newPath.addAll(deltaPath.getSegments());
        }

        return new ItemPath(newPath);

    }

    public static <T extends ObjectType> T getObjectFromReference(ObjectReferenceType ref, Class<T> type) {
        if (ref == null || ref.asReferenceValue().getObject() == null) {
            return null;
        }
        Objectable object = ref.asReferenceValue().getObject().asObjectable();
        if (!type.isAssignableFrom(object.getClass())) {
            throw new IllegalStateException("Got " + object.getClass() + " when expected " + type + ": "
                    + ObjectTypeUtil.toShortString(ref, true));
        }
        return (T) object;
    }

    public static void dispatchToObjectDetailsPage(ObjectReferenceType objectRef, Component component,
            boolean failIfUnsupported) {
        if (objectRef == null) {
            return; // should not occur
        }
        Validate.notNull(objectRef.getOid(), "No OID in objectRef");
        Validate.notNull(objectRef.getType(), "No type in objectRef");
        Class<? extends ObjectType> targetClass = ObjectTypes.getObjectTypeFromTypeQName(objectRef.getType())
                .getClassDefinition();
        dispatchToObjectDetailsPage(targetClass, objectRef.getOid(), component, failIfUnsupported);
    }

    public static void dispatchToObjectDetailsPage(PrismObject obj, Component component) {
        dispatchToObjectDetailsPage(obj, false, component);
    }

    // shows the actual object that is passed via parameter (not its state in repository)
    public static void dispatchToObjectDetailsPage(PrismObject obj, boolean isNewObject, Component component) {
        Class newObjectPageClass = getObjectDetailsPage(obj.getCompileTimeClass());
        if (newObjectPageClass == null) {
            throw new IllegalArgumentException("Cannot determine details page for " + obj.getCompileTimeClass());
        }

        Constructor constructor;
        try {
            constructor = newObjectPageClass.getConstructor(PrismObject.class, boolean.class);

        } catch (NoSuchMethodException | SecurityException e) {
            throw new SystemException(
                    "Unable to locate constructor (PrismObject) in " + newObjectPageClass + ": " + e.getMessage(),
                    e);
        }

        PageBase page;
        try {
            page = (PageBase) constructor.newInstance(obj, isNewObject);
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            throw new SystemException("Error instantiating " + newObjectPageClass + ": " + e.getMessage(), e);
        }

        if (component.getPage() instanceof PageBase) {
            // this way we have correct breadcrumbs
            PageBase pb = (PageBase) component.getPage();
            pb.navigateToNext(page);
        } else {
            component.setResponsePage(page);
        }
    }

    public static void dispatchToObjectDetailsPage(Class<? extends ObjectType> objectClass, String oid,
            Component component, boolean failIfUnsupported) {
        PageParameters parameters = new PageParameters();
        parameters.add(OnePageParameterEncoder.PARAMETER, oid);
        Class<? extends PageBase> page = getObjectDetailsPage(objectClass);
        if (page != null) {
            ((PageBase) component.getPage()).navigateToNext(page, parameters);
        } else if (failIfUnsupported) {
            throw new SystemException("Cannot determine details page for " + objectClass);
        }
    }

    public static boolean hasDetailsPage(PrismObject<?> object) {
        Class<?> clazz = object.getCompileTimeClass();
        return hasDetailsPage(clazz);
    }

    public static boolean hasDetailsPage(Class<?> clazz) {
        return objectDetailsPageMap.containsKey(clazz);
    }

    public static boolean hasDetailsPage(ObjectReferenceType ref) {
        if (ref == null) {
            return false;
        }
        ObjectTypes t = ObjectTypes.getObjectTypeFromTypeQName(ref.getType());
        if (t == null) {
            return false;
        }
        return hasDetailsPage(t.getClassDefinition());
    }

    public static String getStorageKeyForPage(Class<?> pageClass) {
        return storageKeyMap.get(pageClass);
    }

    public static String getStorageKeyForTableId(TableId tableId) {
        return storageTableIdMap.get(tableId);
    }

    public static Class<? extends PageBase> getObjectDetailsPage(Class<? extends ObjectType> type) {
        return objectDetailsPageMap.get(type);
    }

    public static Class<? extends PageBase> getObjectListPage(Class<? extends ObjectType> type) {
        return objectListPageMap.get(type);
    }

    public static String getStorageKeyForObjectClass(Class<? extends ObjectType> type) {
        Class<? extends PageBase> listPageClass = getObjectListPage(type);
        if (listPageClass == null) {
            return null;
        }
        return getStorageKeyForPage(listPageClass);
    }

    @NotNull
    public static TabbedPanel<ITab> createTabPanel(String id, final PageBase parentPage, final List<ITab> tabs,
            TabbedPanel.RightSideItemProvider provider) {
        return createTabPanel(id, parentPage, tabs, provider, null);
    }

    @NotNull
    public static TabbedPanel<ITab> createTabPanel(String id, final PageBase parentPage, final List<ITab> tabs,
            TabbedPanel.RightSideItemProvider provider, final String tabChangeParameter) {

        TabbedPanel<ITab> tabPanel = new TabbedPanel<ITab>(id, tabs, provider) {
            private static final long serialVersionUID = 1L;

            @Override
            protected void onTabChange(int index) {
                if (tabChangeParameter != null) {
                    parentPage.updateBreadcrumbParameters(tabChangeParameter, index);
                }
            }

            @Override
            protected WebMarkupContainer newLink(String linkId, final int index) {
                return new AjaxSubmitLink(linkId) {
                    private static final long serialVersionUID = 1L;

                    @Override
                    protected void onError(AjaxRequestTarget target,
                            org.apache.wicket.markup.html.form.Form<?> form) {
                        super.onError(target, form);
                        target.add(parentPage.getFeedbackPanel());
                    }

                    @Override
                    protected void onSubmit(AjaxRequestTarget target,
                            org.apache.wicket.markup.html.form.Form<?> form) {
                        super.onSubmit(target, form);

                        setSelectedTab(index);
                        if (target != null) {
                            target.add(findParent(TabbedPanel.class));
                        }
                    }

                };
            }
        };
        tabPanel.setOutputMarkupId(true);
        return tabPanel;
    }

    public static Component createHelp(String id) {
        Label helpLabel = new Label(id);
        helpLabel.add(new InfoTooltipBehavior());
        return helpLabel;
    }

    public static String debugDumpComponentTree(Component c) {
        StringBuilder sb = new StringBuilder();
        debugDumpComponentTree(sb, c, 0);
        return sb.toString();

    }

    private static void debugDumpComponentTree(StringBuilder sb, Component c, int level) {
        DebugUtil.indentDebugDump(sb, level);
        sb.append(c).append("\n");
        if (c instanceof MarkupContainer) {
            for (Component sub : (MarkupContainer) c) {
                debugDumpComponentTree(sb, sub, level + 1);
            }
        }
    }

    public static String exceptionToString(String message, Exception e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        pw.println(message);
        e.printStackTrace(pw);
        pw.close();
        return sw.toString();
    }

    public static Behavior visibleIfFalse(final NonEmptyModel<Boolean> model) {
        return new VisibleEnableBehaviour() {
            private static final long serialVersionUID = 1L;

            @Override
            public boolean isVisible() {
                return !model.getObject();
            }
        };
    }

    public static Behavior enabledIfFalse(final NonEmptyModel<Boolean> model) {
        return new VisibleEnableBehaviour() {
            private static final long serialVersionUID = 1L;

            @Override
            public boolean isEnabled() {
                return !model.getObject();
            }
        };
    }

    public static String getStringParameter(PageParameters params, String key) {
        if (params == null || params.get(key) == null) {
            return null;
        }

        StringValue value = params.get(key);
        if (StringUtils.isBlank(value.toString())) {
            return null;
        }

        return value.toString();
    }

    public static Integer getIntegerParameter(PageParameters params, String key) {
        if (params == null || params.get(key) == null) {
            return null;
        }

        StringValue value = params.get(key);
        if (!StringUtils.isNumeric(value.toString())) {
            return null;
        }

        return value.toInteger();
    }

    public static boolean isSubscriptionIdCorrect(String subscriptionId) {
        if (StringUtils.isEmpty(subscriptionId)) {
            return false;
        }
        if (!NumberUtils.isDigits(subscriptionId)) {
            return false;
        }
        if (subscriptionId.length() < 11) {
            return false;
        }
        String subscriptionType = subscriptionId.substring(0, 2);
        boolean isTypeCorrect = false;
        for (SubscriptionType type : SubscriptionType.values()) {
            if (type.getSubscriptionType().equals(subscriptionType)) {
                isTypeCorrect = true;
                break;
            }
        }
        if (!isTypeCorrect) {
            return false;
        }
        String substring1 = subscriptionId.substring(2, 4);
        String substring2 = subscriptionId.substring(4, 6);
        try {
            if (Integer.parseInt(substring1) < 1 || Integer.parseInt(substring1) > 12) {
                return false;
            }

            SimpleDateFormat dateFormat = new SimpleDateFormat("yy");
            String currentYear = dateFormat.format(Calendar.getInstance().getTime());
            if (Integer.parseInt(substring2) < Integer.parseInt(currentYear)) {
                return false;
            }

            String expDateStr = subscriptionId.substring(2, 6);
            dateFormat = new SimpleDateFormat("MMyy");
            Date expDate = dateFormat.parse(expDateStr);
            Date currentDate = new Date(System.currentTimeMillis());
            if (expDate.before(currentDate)) {
                return false;
            }
        } catch (Exception ex) {
            return false;
        }
        VerhoeffCheckDigit checkDigit = new VerhoeffCheckDigit();
        if (checkDigit.isValid(subscriptionId)) {
            return true;
        }
        return false;
    }

    public static void setSelectedTabFromPageParameters(TabbedPanel tabbed, PageParameters params,
            String paramName) {
        IModel<List> tabsModel = tabbed.getTabs();

        Integer tabIndex = getIntegerParameter(params, paramName);
        if (tabIndex == null || tabIndex < 0 || tabIndex >= tabsModel.getObject().size()) {
            return;
        }

        tabbed.setSelectedTab(tabIndex);
    }

    public static boolean getElementVisibility(UserInterfaceElementVisibilityType visibilityType) {
        return getElementVisibility(visibilityType, new ArrayList<>());
    }

    public static boolean getElementVisibility(UserInterfaceElementVisibilityType visibilityType,
            List<String> requiredAuthorizations) {
        if (UserInterfaceElementVisibilityType.HIDDEN.equals(visibilityType)
                || UserInterfaceElementVisibilityType.VACANT.equals(visibilityType)) {
            return false;
        }
        if (UserInterfaceElementVisibilityType.VISIBLE.equals(visibilityType)) {
            return true;
        }
        if (UserInterfaceElementVisibilityType.AUTOMATIC.equals(visibilityType)) {
            if (WebComponentUtil.isAuthorized(requiredAuthorizations)) {
                return true;
            } else {
                return false;
            }
        }
        return true;
    }

    public static <AR extends AbstractRoleType> IModel<String> createAbstractRoleConfirmationMessage(
            String actionName, ColumnMenuAction action, MainObjectListPanel<AR> abstractRoleTable,
            PageBase pageBase) {
        List<AR> selectedRoles = new ArrayList<>();
        if (action.getRowModel() == null) {
            selectedRoles.addAll(abstractRoleTable.getSelectedObjects());
        } else {
            selectedRoles.add(((SelectableBean<AR>) action.getRowModel().getObject()).getValue());
        }
        OperationResult result = new OperationResult("Search Members");
        boolean atLeastOneWithMembers = false;
        for (AR selectedRole : selectedRoles) {
            ObjectQuery query = QueryBuilder.queryFor(FocusType.class, pageBase.getPrismContext())
                    .item(FocusType.F_ROLE_MEMBERSHIP_REF)
                    .ref(ObjectTypeUtil.createObjectRef(selectedRole).asReferenceValue()).maxSize(1).build();
            List<PrismObject<FocusType>> members = WebModelServiceUtils.searchObjects(FocusType.class, query,
                    result, pageBase);
            if (CollectionUtils.isNotEmpty(members)) {
                atLeastOneWithMembers = true;
                break;
            }
        }
        String members = atLeastOneWithMembers ? ".members" : "";
        if (action.getRowModel() == null) {
            return pageBase.createStringResource("pageRoles.message.confirmationMessageForMultipleObject" + members,
                    actionName, abstractRoleTable.getSelectedObjectsCount());
        } else {
            return pageBase.createStringResource("pageRoles.message.confirmationMessageForSingleObject" + members,
                    actionName,
                    ((ObjectType) ((SelectableBean) action.getRowModel().getObject()).getValue()).getName());
        }
    }

    public static List<ItemPath> getShadowItemsToShow() {
        return Arrays.asList(new ItemPath(ShadowType.F_ATTRIBUTES), SchemaConstants.PATH_ACTIVATION,
                SchemaConstants.PATH_PASSWORD, new ItemPath(ShadowType.F_ASSOCIATION));
    }

    public static ItemVisibility checkShadowActivationAndPasswordVisibility(ItemWrapper itemWrapper,
            IModel<ObjectWrapper<ShadowType>> shadowModel) {

        ObjectWrapper<ShadowType> shadowWrapper = shadowModel.getObject();
        PrismObject<ShadowType> shadow = shadowWrapper.getObject();
        ShadowType shadowType = shadow.asObjectable();

        ResourceType resource = shadowType.getResource();
        if (resource == null) {
            //TODO: what to return if we don't have resource available?
            return ItemVisibility.AUTO;
        }

        if (SchemaConstants.PATH_ACTIVATION.equivalent(itemWrapper.getPath())) {
            if (ResourceTypeUtil.isActivationCapabilityEnabled(resource)) {
                return ItemVisibility.AUTO;
            } else {
                return ItemVisibility.HIDDEN;
            }
        }

        if (SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS.equivalent(itemWrapper.getPath())) {
            if (ResourceTypeUtil.isActivationStatusCapabilityEnabled(resource)) {
                return ItemVisibility.AUTO;
            } else {
                return ItemVisibility.HIDDEN;
            }
        }

        if (SchemaConstants.PATH_ACTIVATION_LOCKOUT_STATUS.equivalent(itemWrapper.getPath())) {
            if (ResourceTypeUtil.isActivationLockoutStatusCapabilityEnabled(resource)) {
                return ItemVisibility.AUTO;
            } else {
                return ItemVisibility.HIDDEN;
            }
        }

        if (SchemaConstants.PATH_ACTIVATION_VALID_FROM.equivalent(itemWrapper.getPath())
                || SchemaConstants.PATH_ACTIVATION_VALID_TO.equivalent(itemWrapper.getPath())) {
            if (ResourceTypeUtil.isActivationValidityCapabilityEnabled(resource)) {
                return ItemVisibility.AUTO;
            } else {
                return ItemVisibility.HIDDEN;
            }
        }

        if (SchemaConstants.PATH_PASSWORD.equivalent(itemWrapper.getPath())) {
            if (ResourceTypeUtil.isPasswordCapabilityEnabled(resource)) {
                return ItemVisibility.AUTO;
            } else {
                return ItemVisibility.HIDDEN;
            }
        }

        return ItemVisibility.AUTO;

    }

    public static <T> DropDownChoice createTriStateCombo(String id, IModel<Boolean> model) {
        final IChoiceRenderer<T> renderer = new IChoiceRenderer<T>() {

            @Override
            public T getObject(String id, IModel<? extends List<? extends T>> choices) {
                return id != null ? choices.getObject().get(Integer.parseInt(id)) : null;
            }

            @Override
            public String getDisplayValue(T object) {
                String key;
                if (object == null) {
                    key = KEY_BOOLEAN_NULL;
                } else {
                    Boolean b = (Boolean) object;
                    key = b ? KEY_BOOLEAN_TRUE : KEY_BOOLEAN_FALSE;
                }

                StringResourceModel model = PageBase.createStringResourceStatic(null, key);

                return model.getString();
            }

            @Override
            public String getIdValue(T object, int index) {
                return Integer.toString(index);
            }

        };

        DropDownChoice dropDown = new DropDownChoice(id, model, createChoices(), renderer) {

            @Override
            protected CharSequence getDefaultChoice(String selectedValue) {
                StringResourceModel model = PageBase.createStringResourceStatic(null, KEY_BOOLEAN_NULL);

                return model.getString();
            }
        };
        dropDown.setNullValid(true);

        return dropDown;
    }

    public static boolean isAllNulls(Iterable<?> array) {
        return StreamSupport.stream(array.spliterator(), true).allMatch(o -> o == null);
    }

    public static ObjectFilter createAssociationShadowRefFilter(
            RefinedAssociationDefinition refinedAssocationDefinition, PrismContext prismContext,
            String resourceOid) {
        S_FilterEntryOrEmpty atomicFilter = QueryBuilder.queryFor(ShadowType.class, prismContext);
        List<ObjectFilter> orFilterClauses = new ArrayList<>();
        refinedAssocationDefinition.getIntents().forEach(
                intent -> orFilterClauses.add(atomicFilter.item(ShadowType.F_INTENT).eq(intent).buildFilter()));
        OrFilter intentFilter = OrFilter.createOr(orFilterClauses);

        AndFilter filter = (AndFilter) atomicFilter.item(ShadowType.F_KIND)
                .eq(refinedAssocationDefinition.getKind()).and().item(ShadowType.F_RESOURCE_REF)
                .ref(resourceOid, ResourceType.COMPLEX_TYPE).buildFilter();
        filter.addCondition(intentFilter);
        return filter;
    }

    private static IModel<List<Boolean>> createChoices() {
        return new AbstractReadOnlyModel<List<Boolean>>() {

            @Override
            public List<Boolean> getObject() {
                List<Boolean> list = new ArrayList<>();
                list.add(null);
                list.add(Boolean.TRUE);
                list.add(Boolean.FALSE);

                return list;
            }
        };
    }
}