com.evolveum.midpoint.web.page.admin.server.PageTaskEdit.java Source code

Java tutorial

Introduction

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

Source

/*
 * Copyright (c) 2010-2015 Evolveum
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.evolveum.midpoint.web.page.admin.server;

import com.evolveum.midpoint.common.refinery.RefinedResourceSchema;
import com.evolveum.midpoint.prism.Definition;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.prism.schema.SchemaRegistry;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.processor.ResourceSchema;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
import com.evolveum.midpoint.security.api.AuthorizationConstants;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.task.api.TaskBinding;
import com.evolveum.midpoint.task.api.TaskCategory;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SecurityViolationException;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.application.AuthorizationAction;
import com.evolveum.midpoint.web.application.PageDescriptor;
import com.evolveum.midpoint.web.component.AjaxButton;
import com.evolveum.midpoint.web.component.AjaxSubmitButton;
import com.evolveum.midpoint.web.component.DateInput;
import com.evolveum.midpoint.web.component.data.column.LinkPanel;
import com.evolveum.midpoint.web.component.model.operationStatus.ModelOperationStatusDto;
import com.evolveum.midpoint.web.component.model.operationStatus.ModelOperationStatusPanel;
import com.evolveum.midpoint.web.component.util.LoadableModel;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.page.PageBase;
import com.evolveum.midpoint.web.page.PageTemplate;
import com.evolveum.midpoint.web.page.admin.server.currentState.TaskCurrentStateDtoModel;
import com.evolveum.midpoint.web.page.admin.server.currentState.TaskStatePanel;
import com.evolveum.midpoint.web.page.admin.server.dto.ScheduleValidator;
import com.evolveum.midpoint.web.page.admin.server.dto.StartEndDateValidator;
import com.evolveum.midpoint.web.page.admin.server.dto.TaskAddResourcesDto;
import com.evolveum.midpoint.web.page.admin.server.dto.TaskDto;
import com.evolveum.midpoint.web.page.admin.server.dto.TaskDtoExecutionStatus;
import com.evolveum.midpoint.web.page.admin.server.dto.TaskDtoProviderOptions;
import com.evolveum.midpoint.web.page.admin.server.subtasks.SubtasksPanel;
import com.evolveum.midpoint.web.page.admin.server.workflowInformation.WorkflowInformationPanel;
import com.evolveum.midpoint.web.util.InfoTooltipBehavior;
import com.evolveum.midpoint.web.util.OnePageParameterEncoder;
import com.evolveum.midpoint.web.util.WebMiscUtil;
import com.evolveum.midpoint.web.util.WebModelUtils;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MisfireActionType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ScheduleType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ThreadStopActionType;
import org.apache.commons.lang.StringUtils;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.AjaxSelfUpdatingTimerBehavior;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteTextField;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.EnumChoiceRenderer;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.form.RequiredTextField;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.string.StringValue;
import org.apache.wicket.util.string.Strings;
import org.apache.wicket.util.time.Duration;

import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * @author lazyman
 * @author mserbak
 */
@PageDescriptor(url = "/admin/task", encoder = OnePageParameterEncoder.class, action = {
        @AuthorizationAction(actionUri = PageAdminTasks.AUTHORIZATION_TASKS_ALL, label = PageAdminTasks.AUTH_TASKS_ALL_LABEL, description = PageAdminTasks.AUTH_TASKS_ALL_DESCRIPTION),
        @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_UI_TASK_URL, label = "PageTaskEdit.auth.task.label", description = "PageTaskEdit.auth.task.description") })
public class PageTaskEdit extends PageAdminTasks {

    private static final Trace LOGGER = TraceManager.getTrace(PageTaskEdit.class);
    private static final String DOT_CLASS = PageTaskAdd.class.getName() + ".";
    private static final String OPERATION_LOAD_TASK = DOT_CLASS + "loadTask";
    private static final String OPERATION_SAVE_TASK = DOT_CLASS + "saveTask";
    private static final String OPERATION_SUSPEND_TASKS = DOT_CLASS + "suspendTask";
    private static final String OPERATION_RESUME_TASK = DOT_CLASS + "resumeTask";
    private static final String OPERATION_RUN_NOW_TASK = DOT_CLASS + "runNowTask";
    private static final String OPERATION_LOAD_RESOURCES = DOT_CLASS + "createResourceList";
    private static final String OPERATION_LOAD_RESOURCE = DOT_CLASS + "loadResource";

    private static final String ID_MAIN_FORM = "mainForm";
    private static final String ID_IDENTIFIER = "identifier";
    private static final String ID_HANDLER_URI_LIST = "handlerUriList";
    private static final String ID_HANDLER_URI = "handlerUri";
    private static final String ID_RESOURCE_REF = "resourceRef";
    private static final String ID_KIND = "kind";
    private static final String ID_INTENT = "intent";
    private static final String ID_OBJECT_CLASS = "objectClass";
    private static final String ID_WORKER_THREADS = "workerThreads";
    private static final String ID_MODEL_OPERATION_STATUS_LABEL = "modelOperationStatusLabel";
    private static final String ID_MODEL_OPERATION_STATUS_PANEL = "modelOperationStatusPanel";
    private static final String ID_SUBTASKS_LABEL = "subtasksLabel";
    private static final String ID_SUBTASKS_PANEL = "subtasksPanel";
    private static final String ID_WORKFLOW_INFORMATION_LABEL = "workflowInformationLabel";
    private static final String ID_WORKFLOW_INFORMATION_PANEL = "workflowInformationPanel";
    private static final String ID_TASK_STATE_PANEL = "taskStatePanel";
    private static final String ID_NAME = "name";
    private static final String ID_NAME_LABEL = "nameLabel";
    private static final String ID_DESCRIPTION = "description";
    private static final String ID_DESCRIPTION_LABEL = "descriptionLabel";
    private static final String ID_PARENT = "parent";
    private static final String ID_OPERATION_RESULT_PANEL = "operationResultPanel";
    private static final String ID_SUSPEND = "suspend";
    private static final String ID_RESUME = "resume";
    private static final String ID_RUN_NOW = "runNow";
    private static final String ID_DRY_RUN = "dryRun";

    private IModel<TaskDto> model;
    private static boolean edit = false;

    private PageParameters parameters;

    public PageTaskEdit() {
        this(new PageParameters(), null);
    }

    public PageTaskEdit(PageParameters parameters, PageTemplate previousPage) {

        this.parameters = parameters;
        setPreviousPage(previousPage);

        model = new LoadableModel<TaskDto>(false) {

            @Override
            protected TaskDto load() {
                return loadTask();
            }
        };

        edit = false;
        initLayout();
    }

    private boolean isRunnableOrRunning() {
        TaskDtoExecutionStatus exec = model.getObject().getExecution();
        return TaskDtoExecutionStatus.RUNNABLE.equals(exec) || TaskDtoExecutionStatus.RUNNING.equals(exec);
    }

    private boolean isRunnable() {
        TaskDtoExecutionStatus exec = model.getObject().getExecution();
        return TaskDtoExecutionStatus.RUNNABLE.equals(exec);
    }

    private boolean isRunning() {
        TaskDtoExecutionStatus exec = model.getObject().getExecution();
        return TaskDtoExecutionStatus.RUNNING.equals(exec);
    }

    private boolean isClosed() {
        TaskDtoExecutionStatus exec = model.getObject().getExecution();
        return TaskDtoExecutionStatus.CLOSED.equals(exec);
    }

    private boolean isRecurring() {
        return model.getObject().getRecurring();
    }

    private boolean isSuspended() {
        TaskDtoExecutionStatus exec = model.getObject().getExecution();
        return TaskDtoExecutionStatus.SUSPENDED.equals(exec);
    }

    private TaskDto loadTask() {
        OperationResult result = new OperationResult(OPERATION_LOAD_TASK);
        Task operationTask = getTaskManager().createTaskInstance(OPERATION_LOAD_TASK);

        StringValue taskOid = parameters.get(OnePageParameterEncoder.PARAMETER);

        TaskDto taskDto = null;
        try {
            Collection<SelectorOptions<GetOperationOptions>> options = GetOperationOptions
                    .createRetrieveAttributesOptions(TaskType.F_SUBTASK, TaskType.F_NODE_AS_OBSERVED,
                            TaskType.F_NEXT_RUN_START_TIMESTAMP);
            TaskType loadedTask = getModelService()
                    .getObject(TaskType.class, taskOid.toString(), options, operationTask, result).asObjectable();
            taskDto = prepareTaskDto(loadedTask, result);
            result.computeStatus();
        } catch (Exception ex) {
            result.recordFatalError("Couldn't get task.", ex);
        }

        if (!result.isSuccess()) {
            showResult(result);
        }

        if (taskDto == null) {
            getSession().error(getString("pageTaskEdit.message.cantTaskDetails"));
            if (!result.isSuccess()) {
                showResultInSession(result);
            }
            throw getRestartResponseException(PageTasks.class);
        }
        return taskDto;
    }

    private TaskDto prepareTaskDto(TaskType task, OperationResult result)
            throws SchemaException, ObjectNotFoundException {
        TaskDto taskDto = new TaskDto(task, getModelService(), getTaskService(), getModelInteractionService(),
                getTaskManager(), TaskDtoProviderOptions.fullOptions(), result, this);
        return taskDto;
    }

    private void initLayout() {
        Form mainForm = new Form(ID_MAIN_FORM);
        add(mainForm);

        initMainInfo(mainForm);
        initSchedule(mainForm);

        VisibleEnableBehaviour hiddenWhenEditing = new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                return !edit;
            }
        };

        VisibleEnableBehaviour hiddenWhenEditingOrNoSubtasks = new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                return !edit && !model.getObject().getSubtasks().isEmpty();
            }
        };

        Label subtasksLabel = new Label(ID_SUBTASKS_LABEL, new ResourceModel("pageTaskEdit.subtasksLabel"));
        subtasksLabel.add(hiddenWhenEditingOrNoSubtasks);
        mainForm.add(subtasksLabel);
        SubtasksPanel subtasksPanel = new SubtasksPanel(ID_SUBTASKS_PANEL,
                new PropertyModel<List<TaskDto>>(model, TaskDto.F_SUBTASKS), getWorkflowManager().isEnabled());
        subtasksPanel.add(hiddenWhenEditingOrNoSubtasks);
        mainForm.add(subtasksPanel);

        VisibleEnableBehaviour hiddenWhenEditingOrNoWorkflowInformation = new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                return !edit && model.getObject().isWorkflowShadowTask() && getWorkflowManager().isEnabled();
            }
        };

        Label workflowInformationLabel = new Label(ID_WORKFLOW_INFORMATION_LABEL,
                new ResourceModel("pageTaskEdit.workflowInformationLabel"));
        workflowInformationLabel.add(hiddenWhenEditingOrNoWorkflowInformation);
        mainForm.add(workflowInformationLabel);

        WorkflowInformationPanel workflowInformationPanel = new WorkflowInformationPanel(
                ID_WORKFLOW_INFORMATION_PANEL, model);
        workflowInformationPanel.add(hiddenWhenEditingOrNoWorkflowInformation);
        mainForm.add(workflowInformationPanel);

        VisibleEnableBehaviour modelOpBehaviour = new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                return !edit && model.getObject().getModelOperationStatus() != null;
            }
        };
        Label modelOperationStatusLabel = new Label(ID_MODEL_OPERATION_STATUS_LABEL,
                new ResourceModel("pageTaskEdit.modelOperationStatusLabel"));
        modelOperationStatusLabel.add(modelOpBehaviour);
        mainForm.add(modelOperationStatusLabel);
        ModelOperationStatusPanel panel = new ModelOperationStatusPanel(ID_MODEL_OPERATION_STATUS_PANEL,
                new PropertyModel<ModelOperationStatusDto>(model, TaskDto.F_MODEL_OPERATION_STATUS));
        panel.add(modelOpBehaviour);
        mainForm.add(panel);

        final TaskStatePanel taskStatePanel = new TaskStatePanel(ID_TASK_STATE_PANEL,
                new TaskCurrentStateDtoModel(model), this);
        taskStatePanel.add(hiddenWhenEditing);
        AjaxSelfUpdatingTimerBehavior refreshingBehavior = new AjaxSelfUpdatingTimerBehavior(
                Duration.milliseconds(1000)) {
            @Override
            protected void onPostProcessTarget(AjaxRequestTarget target) {
                taskStatePanel.refreshModel(PageTaskEdit.this);
            }
        };
        taskStatePanel.add(refreshingBehavior);

        mainForm.add(taskStatePanel);

        DropDownChoice threadStop = new DropDownChoice<>("threadStop", new Model<ThreadStopActionType>() {

            @Override
            public ThreadStopActionType getObject() {
                return model.getObject().getThreadStop();
            }

            @Override
            public void setObject(ThreadStopActionType object) {
                model.getObject().setThreadStop(object);
            }
        }, WebMiscUtil.createReadonlyModelFromEnum(ThreadStopActionType.class),
                new EnumChoiceRenderer<ThreadStopActionType>(PageTaskEdit.this));
        threadStop.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isEnabled() {
                return edit;
            }
        });
        mainForm.add(threadStop);

        //mainForm.add(new TsaValidator(runUntilNodeDown, threadStop));

        CheckBox dryRun = new CheckBox(ID_DRY_RUN, new PropertyModel<Boolean>(model, TaskDto.F_DRY_RUN));
        dryRun.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isEnabled() {
                return edit;
            }
        });
        mainForm.add(dryRun);

        initButtons(mainForm);
    }

    private void initMainInfo(Form mainForm) {
        RequiredTextField<String> name = new RequiredTextField<>(ID_NAME,
                new PropertyModel<String>(model, TaskDto.F_NAME));
        name.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isVisible() {
                return edit;
            }
        });
        name.add(new AttributeModifier("style", "width: 100%"));
        name.add(new EmptyOnBlurAjaxFormUpdatingBehaviour());
        mainForm.add(name);

        Label nameLabel = new Label(ID_NAME_LABEL, new PropertyModel(model, TaskDto.F_NAME));
        nameLabel.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                return !edit;
            }
        });
        mainForm.add(nameLabel);

        TextArea<String> description = new TextArea<>(ID_DESCRIPTION,
                new PropertyModel<String>(model, TaskDto.F_DESCRIPTION));
        description.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isVisible() {
                return edit;
            }
        });
        //        description.add(new AttributeModifier("style", "width: 100%"));
        //        description.add(new EmptyOnBlurAjaxFormUpdatingBehaviour());
        mainForm.add(description);

        Label descriptionLabel = new Label(ID_DESCRIPTION_LABEL, new PropertyModel(model, TaskDto.F_DESCRIPTION));
        descriptionLabel.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                return !edit;
            }
        });
        mainForm.add(descriptionLabel);

        Label oid = new Label("oid", new PropertyModel(model, "oid"));
        mainForm.add(oid);

        mainForm.add(new Label(ID_IDENTIFIER, new PropertyModel(model, TaskDto.F_IDENTIFIER)));

        Label category = new Label("category", new PropertyModel(model, "category"));
        mainForm.add(category);

        LinkPanel parent = new LinkPanel(ID_PARENT, new PropertyModel<>(model, TaskDto.F_PARENT_TASK_NAME)) {
            @Override
            public void onClick(AjaxRequestTarget target) {
                String oid = model.getObject().getParentTaskOid();
                if (oid != null) {
                    PageParameters parameters = new PageParameters();
                    parameters.add(OnePageParameterEncoder.PARAMETER, oid);
                    setResponsePage(new PageTaskEdit(parameters, PageTaskEdit.this));
                }
            }
        };
        mainForm.add(parent);

        ListView<String> handlerUriList = new ListView<String>(ID_HANDLER_URI_LIST,
                new PropertyModel(model, TaskDto.F_HANDLER_URI_LIST)) {
            @Override
            protected void populateItem(ListItem<String> item) {
                item.add(new Label(ID_HANDLER_URI, item.getModelObject()));
            }
        };
        mainForm.add(handlerUriList);
        //      Label uri = new Label(ID_HANDLER_URI, new PropertyModel(model, "uri"));
        //      mainForm.add(uri);

        Label execution = new Label("execution", new AbstractReadOnlyModel<String>() {

            @Override
            public String getObject() {
                TaskDtoExecutionStatus executionStatus = model.getObject().getExecution();
                if (executionStatus != TaskDtoExecutionStatus.CLOSED) {
                    return getString(TaskDtoExecutionStatus.class.getSimpleName() + "." + executionStatus.name());
                } else {
                    return getString(TaskDtoExecutionStatus.class.getSimpleName() + "." + executionStatus.name()
                            + ".withTimestamp", new AbstractReadOnlyModel<String>() {
                                @Override
                                public String getObject() {
                                    if (model.getObject().getCompletionTimestamp() != null) {
                                        return new Date(model.getObject().getCompletionTimestamp())
                                                .toLocaleString(); // todo correct formatting
                                    } else {
                                        return "?";
                                    }
                                }
                            });
                }
            }
        });
        mainForm.add(execution);

        final DropDownChoice<TaskAddResourcesDto> resource = new DropDownChoice<>(ID_RESOURCE_REF,
                new PropertyModel<TaskAddResourcesDto>(model, TaskDto.F_RESOURCE_REFERENCE),
                new AbstractReadOnlyModel<List<TaskAddResourcesDto>>() {

                    @Override
                    public List<TaskAddResourcesDto> getObject() {
                        return createResourceList();
                    }
                }, new IChoiceRenderer<TaskAddResourcesDto>() {

                    @Override
                    public Object getDisplayValue(TaskAddResourcesDto object) {
                        return object.getName();
                    }

                    @Override
                    public String getIdValue(TaskAddResourcesDto object, int index) {
                        return Integer.toString(index);
                    }
                });
        resource.setOutputMarkupId(true);
        resource.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isEnabled() {
                if (!edit) {
                    return false;
                }

                TaskDto dto = model.getObject();
                boolean sync = TaskCategory.LIVE_SYNCHRONIZATION.equals(dto.getCategory());
                boolean recon = TaskCategory.RECONCILIATION.equals(dto.getCategory());
                boolean importAccounts = TaskCategory.IMPORTING_ACCOUNTS.equals(dto.getCategory());
                return sync || recon || importAccounts;
            }
        });
        resource.add(new AjaxFormComponentUpdatingBehavior("onchange") {

            @Override
            protected void onUpdate(AjaxRequestTarget target) {
                Task task = createSimpleTask(OPERATION_LOAD_RESOURCE);
                OperationResult result = task.getResult();
                List<QName> objectClassList = new ArrayList<>();

                TaskAddResourcesDto resourcesDto = model.getObject().getResource();

                if (resourcesDto != null) {
                    PrismObject<ResourceType> resource = WebModelUtils.loadObject(ResourceType.class,
                            resourcesDto.getOid(), PageTaskEdit.this, task, result);

                    try {
                        ResourceSchema schema = RefinedResourceSchema.getResourceSchema(resource,
                                getPrismContext());
                        schema.getObjectClassDefinitions();

                        for (Definition def : schema.getDefinitions()) {
                            objectClassList.add(def.getTypeName());
                        }

                        model.getObject().setObjectClassList(objectClassList);
                    } catch (Exception e) {
                        LoggingUtils.logException(LOGGER, "Couldn't load object class list from resource.", e);
                        error("Couldn't load object class list from resource.");
                    }

                }

                target.add(get(ID_MAIN_FORM + ":" + ID_OBJECT_CLASS));
            }
        });
        mainForm.add(resource);

        final DropDownChoice kind = new DropDownChoice<>(ID_KIND,
                new PropertyModel<ShadowKindType>(model, TaskDto.F_KIND),
                new AbstractReadOnlyModel<List<ShadowKindType>>() {

                    @Override
                    public List<ShadowKindType> getObject() {
                        return createShadowKindTypeList();
                    }
                }, new IChoiceRenderer<ShadowKindType>() {

                    @Override
                    public Object getDisplayValue(ShadowKindType object) {
                        return object.value();
                    }

                    @Override
                    public String getIdValue(ShadowKindType object, int index) {
                        return Integer.toString(index);
                    }
                });
        kind.setOutputMarkupId(true);
        kind.setNullValid(true);
        kind.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isEnabled() {
                if (!edit) {
                    return false;
                }

                TaskDto dto = model.getObject();
                boolean sync = TaskCategory.LIVE_SYNCHRONIZATION.equals(dto.getCategory());
                boolean recon = TaskCategory.RECONCILIATION.equals(dto.getCategory());
                boolean importAccounts = TaskCategory.IMPORTING_ACCOUNTS.equals(dto.getCategory());
                return sync || recon || importAccounts;
            }
        });
        mainForm.add(kind);

        final TextField<String> intent = new TextField<>(ID_INTENT,
                new PropertyModel<String>(model, TaskDto.F_INTENT));
        mainForm.add(intent);
        intent.setOutputMarkupId(true);
        intent.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isEnabled() {
                if (!edit) {
                    return false;
                }

                TaskDto dto = model.getObject();
                boolean sync = TaskCategory.LIVE_SYNCHRONIZATION.equals(dto.getCategory());
                boolean recon = TaskCategory.RECONCILIATION.equals(dto.getCategory());
                boolean importAccounts = TaskCategory.IMPORTING_ACCOUNTS.equals(dto.getCategory());
                return sync || recon || importAccounts;
            }
        });

        AutoCompleteSettings autoCompleteSettings = new AutoCompleteSettings();
        autoCompleteSettings.setShowListOnEmptyInput(true);
        final AutoCompleteTextField<String> objectClass = new AutoCompleteTextField<String>(ID_OBJECT_CLASS,
                new PropertyModel<String>(model, TaskDto.F_OBJECT_CLASS), autoCompleteSettings) {

            @Override
            protected Iterator<String> getChoices(String input) {

                return prepareObjectClassChoiceList(input);
            }
        };
        objectClass.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isEnabled() {
                if (!edit) {
                    return false;
                }

                TaskDto dto = model.getObject();
                boolean sync = TaskCategory.LIVE_SYNCHRONIZATION.equals(dto.getCategory());
                boolean recon = TaskCategory.RECONCILIATION.equals(dto.getCategory());
                boolean importAccounts = TaskCategory.IMPORTING_ACCOUNTS.equals(dto.getCategory());
                return sync || recon || importAccounts;
            }
        });
        mainForm.add(objectClass);

        final TextField<Integer> workerThreads = new TextField<>(ID_WORKER_THREADS,
                new PropertyModel<Integer>(model, TaskDto.F_WORKER_THREADS));
        mainForm.add(workerThreads);
        workerThreads.setOutputMarkupId(true);
        workerThreads.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isEnabled() {
                return edit;
            }

            @Override
            public boolean isVisible() {
                TaskDto dto = model.getObject();
                return TaskCategory.RECONCILIATION.equals(dto.getCategory())
                        || TaskCategory.IMPORTING_ACCOUNTS.equals(dto.getCategory())
                        || TaskCategory.RECOMPUTATION.equals(dto.getCategory());
            }
        });

        Label node = new Label("node", new AbstractReadOnlyModel<String>() {
            @Override
            public String getObject() {
                TaskDto dto = model.getObject();
                if (!TaskDtoExecutionStatus.RUNNING.equals(dto.getExecution())) {
                    return null;
                }
                return PageTaskEdit.this.getString("pageTaskEdit.message.node", dto.getExecutingAt());
            }
        });
        mainForm.add(node);
    }

    private Iterator<String> prepareObjectClassChoiceList(String input) {
        List<String> choices = new ArrayList<>();

        if (model.getObject().getResource() == null) {
            return choices.iterator();
        }

        if (Strings.isEmpty(input)) {
            for (QName q : model.getObject().getObjectClassList()) {
                choices.add(q.getLocalPart());
                Collections.sort(choices);
            }
        } else {
            for (QName q : model.getObject().getObjectClassList()) {
                if (q.getLocalPart().startsWith(input)) {
                    choices.add(q.getLocalPart());
                }
                Collections.sort(choices);
            }
        }

        return choices.iterator();
    }

    private List<ShadowKindType> createShadowKindTypeList() {
        List<ShadowKindType> kindList = new ArrayList<>();

        kindList.add(ShadowKindType.ACCOUNT);
        kindList.add(ShadowKindType.ENTITLEMENT);
        kindList.add(ShadowKindType.GENERIC);

        return kindList;
    }

    private void initSchedule(Form mainForm) {
        //todo probably can be removed, visibility can be updated in children (already components) [lazyman]
        final WebMarkupContainer container = new WebMarkupContainer("container");
        container.setOutputMarkupId(true);
        mainForm.add(container);

        final IModel<Boolean> recurringCheck = new PropertyModel<Boolean>(model, "recurring");
        final IModel<Boolean> boundCheck = new PropertyModel<Boolean>(model, "bound");

        WebMarkupContainer suspendReqRecurring = new WebMarkupContainer("suspendReqRecurring");
        suspendReqRecurring.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                return edit && isRunnableOrRunning();
            }
        });
        mainForm.add(suspendReqRecurring);

        final WebMarkupContainer boundContainer = new WebMarkupContainer("boundContainer");
        boundContainer.add(new VisibleEnableBehaviour() {

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

        });
        boundContainer.setOutputMarkupId(true);
        container.add(boundContainer);

        WebMarkupContainer suspendReqBound = new WebMarkupContainer("suspendReqBound");
        suspendReqBound.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                return edit && isRunnableOrRunning();
            }
        });
        boundContainer.add(suspendReqBound);

        final WebMarkupContainer intervalContainer = new WebMarkupContainer("intervalContainer");
        intervalContainer.add(new VisibleEnableBehaviour() {

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

        });
        intervalContainer.setOutputMarkupId(true);
        container.add(intervalContainer);

        final WebMarkupContainer cronContainer = new WebMarkupContainer("cronContainer");
        cronContainer.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isVisible() {
                return recurringCheck.getObject() && !boundCheck.getObject();
            }

        });
        cronContainer.setOutputMarkupId(true);
        container.add(cronContainer);
        AjaxCheckBox recurring = new AjaxCheckBox("recurring", recurringCheck) {

            @Override
            protected void onUpdate(AjaxRequestTarget target) {
                target.add(container);
                target.add(PageTaskEdit.this.get("mainForm:recurring"));
            }
        };
        recurring.setOutputMarkupId(true);
        recurring.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isEnabled() {
                return edit && !isRunnableOrRunning();
            }
        });
        mainForm.add(recurring);

        final AjaxCheckBox bound = new AjaxCheckBox("bound", boundCheck) {

            @Override
            protected void onUpdate(AjaxRequestTarget target) {
                target.add(container);
                target.add(PageTaskEdit.this.get("mainForm:recurring"));
            }
        };
        bound.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isEnabled() {
                return edit && !isRunnableOrRunning();
            }
        });
        boundContainer.add(bound);

        Label boundHelp = new Label("boundHelp");
        boundHelp.add(new InfoTooltipBehavior());
        boundContainer.add(boundHelp);

        TextField<Integer> interval = new TextField<Integer>("interval",
                new PropertyModel<Integer>(model, "interval"));
        interval.add(new EmptyOnBlurAjaxFormUpdatingBehaviour());
        interval.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isEnabled() {
                return edit && (!isRunnableOrRunning() || !boundCheck.getObject());
            }
        });
        intervalContainer.add(interval);

        TextField<String> cron = new TextField<String>("cron",
                new PropertyModel<String>(model, "cronSpecification"));
        cron.add(new EmptyOnBlurAjaxFormUpdatingBehaviour());
        cron.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isEnabled() {
                return edit && (!isRunnableOrRunning() || !boundCheck.getObject());
            }
        });
        cronContainer.add(cron);

        Label cronHelp = new Label("cronHelp");
        cronHelp.add(new InfoTooltipBehavior());
        cronContainer.add(cronHelp);

        DateInput notStartBefore = new DateInput("notStartBeforeField",
                new PropertyModel<Date>(model, "notStartBefore"));
        notStartBefore.setOutputMarkupId(true);
        notStartBefore.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isEnabled() {
                return edit && !isRunning();
            }
        });
        mainForm.add(notStartBefore);

        DateInput notStartAfter = new DateInput("notStartAfterField",
                new PropertyModel<Date>(model, "notStartAfter"));
        notStartAfter.setOutputMarkupId(true);
        notStartAfter.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isEnabled() {
                return edit;
            }
        });
        mainForm.add(notStartAfter);

        DropDownChoice misfire = new DropDownChoice("misfireAction",
                new PropertyModel<MisfireActionType>(model, "misfireAction"),
                WebMiscUtil.createReadonlyModelFromEnum(MisfireActionType.class),
                new EnumChoiceRenderer<MisfireActionType>(PageTaskEdit.this));
        misfire.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isEnabled() {
                return edit;
            }
        });
        mainForm.add(misfire);

        Label lastStart = new Label("lastStarted", new AbstractReadOnlyModel<String>() {

            @Override
            public String getObject() {
                TaskDto dto = model.getObject();
                if (dto.getLastRunStartTimestampLong() == null) {
                    return "-";
                }
                Date date = new Date(dto.getLastRunStartTimestampLong());
                return WebMiscUtil.formatDate(date);
            }

        });
        mainForm.add(lastStart);

        Label lastFinished = new Label("lastFinished", new AbstractReadOnlyModel<String>() {

            @Override
            public String getObject() {
                TaskDto dto = model.getObject();
                if (dto.getLastRunFinishTimestampLong() == null) {
                    return "-";
                }
                Date date = new Date(dto.getLastRunFinishTimestampLong());
                return WebMiscUtil.formatDate(date);
            }
        });
        mainForm.add(lastFinished);

        Label nextRun = new Label("nextRun", new AbstractReadOnlyModel<String>() {

            @Override
            public String getObject() {
                TaskDto dto = model.getObject();
                if (dto.getRecurring() && dto.getBound() && isRunning()) {
                    return getString("pageTasks.runsContinually");
                }
                if (dto.getNextRunStartTimeLong() == null) {
                    return "-";
                }
                Date date = new Date(dto.getNextRunStartTimeLong());
                return WebMiscUtil.formatDate(date);
            }
        });
        mainForm.add(nextRun);

        mainForm.add(new StartEndDateValidator(notStartBefore, notStartAfter));
        mainForm.add(new ScheduleValidator(getTaskManager(), recurring, bound, interval, cron));
    }

    private void initButtons(final Form mainForm) {
        AjaxButton backButton = new AjaxButton("backButton", createStringResource("pageTaskEdit.button.back")) {

            @Override
            public void onClick(AjaxRequestTarget target) {
                edit = false;
                goBack(PageTasks.class);
            }
        };
        mainForm.add(backButton);

        AjaxSubmitButton saveButton = new AjaxSubmitButton("saveButton",
                createStringResource("pageTaskEdit.button.save")) {

            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                savePerformed(target);
            }

            @Override
            protected void onError(AjaxRequestTarget target, Form<?> form) {
                target.add(getFeedbackPanel());
            }

        };
        saveButton.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                return edit;
            }
        });
        mainForm.setDefaultButton(saveButton);
        mainForm.add(saveButton);

        AjaxButton editButton = new AjaxButton("editButton", createStringResource("pageTaskEdit.button.edit")) {

            @Override
            public void onClick(AjaxRequestTarget target) {
                edit = true;
                target.add(mainForm);
            }
        };
        editButton.add(new VisibleEnableBehaviour() {
            @Override
            public boolean isVisible() {
                return !edit;
            }
        });
        mainForm.add(editButton);

        AjaxButton suspend = new AjaxButton(ID_SUSPEND, createStringResource("pageTaskEdit.button.suspend")) {

            @Override
            public void onClick(AjaxRequestTarget target) {
                suspendPerformed(target);
            }
        };
        suspend.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isVisible() {
                return !edit && isRunnableOrRunning();
            }
        });
        mainForm.add(suspend);

        AjaxButton resume = new AjaxButton(ID_RESUME, createStringResource("pageTaskEdit.button.resume")) {

            @Override
            public void onClick(AjaxRequestTarget target) {
                resumePerformed(target);
            }
        };
        resume.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isVisible() {
                return !edit && (isSuspended() || (isClosed() && isRecurring()));
            }
        });
        mainForm.add(resume);

        AjaxButton runNow = new AjaxButton(ID_RUN_NOW, createStringResource("pageTaskEdit.button.runNow")) {

            @Override
            public void onClick(AjaxRequestTarget target) {
                runNowPerformed(target);
            }
        };
        runNow.add(new VisibleEnableBehaviour() {

            @Override
            public boolean isVisible() {
                return !edit && (isRunnable() || (isClosed() && !isRecurring()));
            }
        });
        mainForm.add(runNow);
    }

    private List<TaskAddResourcesDto> createResourceList() {
        OperationResult result = new OperationResult(OPERATION_LOAD_RESOURCES);
        Task task = createSimpleTask(OPERATION_LOAD_RESOURCES);
        List<PrismObject<ResourceType>> resources = null;
        List<TaskAddResourcesDto> resourceList = new ArrayList<>();

        try {
            resources = getModelService().searchObjects(ResourceType.class, new ObjectQuery(), null, task, result);
            result.recomputeStatus();
        } catch (Exception ex) {
            result.recordFatalError("Couldn't get resource list.", ex);
            LoggingUtils.logException(LOGGER, "Couldn't get resource list", ex);
        }

        if (resources != null) {
            ResourceType item = null;
            for (PrismObject<ResourceType> resource : resources) {
                item = resource.asObjectable();
                resourceList.add(
                        new TaskAddResourcesDto(item.getOid(), WebMiscUtil.getOrigStringFromPoly(item.getName())));
            }
        }
        return resourceList;
    }

    private void savePerformed(AjaxRequestTarget target) {
        LOGGER.debug("Saving new task.");
        OperationResult result = new OperationResult(OPERATION_SAVE_TASK);
        TaskDto dto = model.getObject();
        Task operationTask = createSimpleTask(OPERATION_SAVE_TASK);
        TaskManager manager = getTaskManager();

        try {
            PrismObject<TaskType> originalTaskType = getModelService().getObject(TaskType.class, dto.getOid(), null,
                    operationTask, result);
            Task originalTask = manager.createTaskInstance(originalTaskType, result);
            Task updatedTask = updateTask(dto, originalTask);

            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Saving task modifications.");
            }
            getModelService().executeChanges(prepareChanges(updatedTask), null, operationTask, result);

            edit = false;
            setResponsePage(new PageTasks(false));
            result.recomputeStatus();
        } catch (Exception ex) {
            result.recomputeStatus();
            result.recordFatalError("Couldn't save task.", ex);
            LoggingUtils.logException(LOGGER, "Couldn't save task modifications", ex);
        }
        showResultInSession(result);
        target.add(getFeedbackPanel());
    }

    private List<ObjectDelta<? extends ObjectType>> prepareChanges(Task updatedTask) {
        Collection<? extends ItemDelta<?, ?>> modifications = updatedTask.getPendingModifications();
        List<ObjectDelta<? extends ObjectType>> retval = new ArrayList<ObjectDelta<? extends ObjectType>>();
        retval.add(ObjectDelta.createModifyDelta(updatedTask.getOid(), modifications, TaskType.class,
                getPrismContext()));
        return retval;
    }

    private Task updateTask(TaskDto dto, Task existingTask) throws SchemaException {

        if (!existingTask.getName().equals(dto.getName())) {
            existingTask.setName(WebMiscUtil.createPolyFromOrigString(dto.getName()));
        } // if they are equal, modifyObject complains ... it's probably a bug in repo; we'll fix it later?

        if ((existingTask.getDescription() == null && dto.getDescription() != null)
                || (existingTask.getDescription() != null
                        && !existingTask.getDescription().equals(dto.getDescription()))) {
            existingTask.setDescription(dto.getDescription());
        }

        TaskAddResourcesDto resourceRefDto;
        if (dto.getResource() != null) {
            resourceRefDto = dto.getResource();
            ObjectReferenceType resourceRef = new ObjectReferenceType();
            resourceRef.setOid(resourceRefDto.getOid());
            resourceRef.setType(ResourceType.COMPLEX_TYPE);
            existingTask.setObjectRef(resourceRef);
        }

        if (!dto.getRecurring()) {
            existingTask.makeSingle();
        }
        existingTask.setBinding(dto.getBound() == true ? TaskBinding.TIGHT : TaskBinding.LOOSE);

        ScheduleType schedule = new ScheduleType();

        schedule.setEarliestStartTime(MiscUtil.asXMLGregorianCalendar(dto.getNotStartBefore()));
        schedule.setLatestStartTime(MiscUtil.asXMLGregorianCalendar(dto.getNotStartAfter()));
        schedule.setMisfireAction(dto.getMisfire());
        if (existingTask.getSchedule() != null) {
            schedule.setLatestFinishTime(existingTask.getSchedule().getLatestFinishTime());
        }

        if (dto.getRecurring() == true) {

            if (dto.getBound() == false && dto.getCronSpecification() != null) {
                schedule.setCronLikePattern(dto.getCronSpecification());
            } else {
                schedule.setInterval(dto.getInterval());
            }
            existingTask.makeRecurring(schedule);
        } else {
            existingTask.makeSingle(schedule);
        }

        ThreadStopActionType tsa = dto.getThreadStop();
        //        if (tsa == null) {
        //            tsa = dto.getRunUntilNodeDown() ? ThreadStopActionType.CLOSE : ThreadStopActionType.RESTART;
        //        }
        existingTask.setThreadStopAction(tsa);

        SchemaRegistry registry = getPrismContext().getSchemaRegistry();
        if (dto.isDryRun()) {
            PrismPropertyDefinition def = registry
                    .findPropertyDefinitionByElementName(SchemaConstants.MODEL_EXTENSION_DRY_RUN);
            PrismProperty dryRun = new PrismProperty(SchemaConstants.MODEL_EXTENSION_DRY_RUN);
            dryRun.setDefinition(def);
            dryRun.setRealValue(true);

            existingTask.addExtensionProperty(dryRun);
        } else {
            PrismProperty dryRun = existingTask.getExtensionProperty(SchemaConstants.MODEL_EXTENSION_DRY_RUN);
            if (dryRun != null) {
                existingTask.deleteExtensionProperty(dryRun);
            }
        }

        if (dto.getKind() != null) {
            PrismPropertyDefinition def = registry
                    .findPropertyDefinitionByElementName(SchemaConstants.MODEL_EXTENSION_KIND);
            PrismProperty kind = new PrismProperty(SchemaConstants.MODEL_EXTENSION_KIND);
            kind.setDefinition(def);
            kind.setRealValue(dto.getKind());

            existingTask.addExtensionProperty(kind);
        } else {
            PrismProperty kind = existingTask.getExtensionProperty(SchemaConstants.MODEL_EXTENSION_KIND);

            if (kind != null) {
                existingTask.deleteExtensionProperty(kind);
            }
        }

        if (dto.getIntent() != null && StringUtils.isNotEmpty(dto.getIntent())) {
            PrismPropertyDefinition def = registry
                    .findPropertyDefinitionByElementName(SchemaConstants.MODEL_EXTENSION_INTENT);
            PrismProperty intent = new PrismProperty(SchemaConstants.MODEL_EXTENSION_INTENT);
            intent.setDefinition(def);
            intent.setRealValue(dto.getIntent());

            existingTask.addExtensionProperty(intent);
        } else {
            PrismProperty intent = existingTask.getExtensionProperty(SchemaConstants.MODEL_EXTENSION_INTENT);

            if (intent != null) {
                existingTask.deleteExtensionProperty(intent);
            }
        }

        if (dto.getObjectClass() != null && StringUtils.isNotEmpty(dto.getObjectClass())) {
            PrismPropertyDefinition def = registry
                    .findPropertyDefinitionByElementName(SchemaConstants.OBJECTCLASS_PROPERTY_NAME);
            PrismProperty objectClassProperty = new PrismProperty(SchemaConstants.OBJECTCLASS_PROPERTY_NAME);
            objectClassProperty.setRealValue(def);

            QName objectClass = null;
            for (QName q : model.getObject().getObjectClassList()) {
                if (q.getLocalPart().equals(dto.getObjectClass())) {
                    objectClass = q;
                }
            }

            objectClassProperty.setRealValue(objectClass);
            existingTask.addExtensionProperty(objectClassProperty);

        } else {
            PrismProperty objectClass = existingTask
                    .getExtensionProperty(SchemaConstants.OBJECTCLASS_PROPERTY_NAME);

            if (objectClass != null) {
                existingTask.deleteExtensionProperty(objectClass);
            }
        }

        if (dto.getWorkerThreads() != null) {
            PrismPropertyDefinition def = registry
                    .findPropertyDefinitionByElementName(SchemaConstants.MODEL_EXTENSION_WORKER_THREADS);
            PrismProperty workerThreads = new PrismProperty(SchemaConstants.MODEL_EXTENSION_WORKER_THREADS);
            workerThreads.setDefinition(def);
            workerThreads.setRealValue(dto.getWorkerThreads());

            existingTask.setExtensionProperty(workerThreads);
        } else {
            PrismProperty workerThreads = existingTask
                    .getExtensionProperty(SchemaConstants.MODEL_EXTENSION_WORKER_THREADS);

            if (workerThreads != null) {
                existingTask.deleteExtensionProperty(workerThreads);
            }
        }

        return existingTask;
    }

    private void suspendPerformed(AjaxRequestTarget target) {
        String oid = model.getObject().getOid();
        OperationResult result = new OperationResult(OPERATION_SUSPEND_TASKS);
        try {
            boolean suspended = getTaskService().suspendTasks(Collections.singleton(oid),
                    PageTasks.WAIT_FOR_TASK_STOP, result);

            result.computeStatus();
            if (result.isSuccess()) {
                if (suspended) {
                    result.recordStatus(OperationResultStatus.SUCCESS,
                            "The task have been successfully suspended.");
                } else {
                    result.recordWarning(
                            "Task suspension has been successfully requested; please check for its completion using task list.");
                }
            }
        } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | RuntimeException e) {
            result.recordFatalError("Couldn't suspend the task", e);
        }

        showResultInSession(result);
        setResponsePage(new PageTasks(false));
    }

    private void resumePerformed(AjaxRequestTarget target) {
        String oid = model.getObject().getOid();
        OperationResult result = new OperationResult(OPERATION_RESUME_TASK);
        try {
            getTaskService().resumeTasks(Arrays.asList(oid), result);
            result.computeStatus();

            if (result.isSuccess()) {
                result.recordStatus(OperationResultStatus.SUCCESS, "The task has been successfully resumed.");
            }
        } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | RuntimeException e) {
            result.recordFatalError("Couldn't resume the task", e);
        }

        showResultInSession(result);
        setResponsePage(new PageTasks(false));
    }

    private void runNowPerformed(AjaxRequestTarget target) {
        String oid = model.getObject().getOid();
        OperationResult result = new OperationResult(OPERATION_RUN_NOW_TASK);
        try {
            getTaskService().scheduleTasksNow(Arrays.asList(oid), result);
            result.computeStatus();

            if (result.isSuccess()) {
                result.recordStatus(OperationResultStatus.SUCCESS,
                        "The task has been successfully scheduled to run.");
            }
        } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | RuntimeException e) {
            result.recordFatalError("Couldn't schedule the task", e);
        }

        showResultInSession(result);
        setResponsePage(new PageTasks(false));
    }

    private static class EmptyOnBlurAjaxFormUpdatingBehaviour extends AjaxFormComponentUpdatingBehavior {

        public EmptyOnBlurAjaxFormUpdatingBehaviour() {
            super("onBlur");
        }

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

    @Override
    public PageBase reinitialize() {
        return new PageTaskEdit(parameters, getPreviousPage());
    }
}