/* * Copyright (c) 2010-2016 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.evolveum.midpoint.web.page.admin.server; import com.evolveum.midpoint.gui.api.model.LoadableModel; import com.evolveum.midpoint.model.api.ModelAuthorizationAction; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.application.AuthorizationAction; import com.evolveum.midpoint.web.application.PageDescriptor; import com.evolveum.midpoint.web.component.prism.ContainerStatus; import com.evolveum.midpoint.web.component.prism.ObjectWrapper; import com.evolveum.midpoint.web.component.prism.ObjectWrapperFactory; import com.evolveum.midpoint.web.component.refresh.AutoRefreshDto; import com.evolveum.midpoint.web.component.refresh.AutoRefreshPanel; import com.evolveum.midpoint.web.component.refresh.Refreshable; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.page.admin.PageAdmin; 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.util.OnePageParameterEncoder; import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; import com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.request.mapper.parameter.PageParameters; import javax.xml.namespace.QName; import java.util.Collection; /** * @author mederly */ @PageDescriptor(url = "/admin/task2", 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 PageAdmin implements Refreshable { private static final int REFRESH_INTERVAL_IF_RUNNABLE = 2000; private static final int REFRESH_INTERVAL_IF_SUSPENDED = 60000; private static final int REFRESH_INTERVAL_IF_WAITING = 60000; private static final int REFRESH_INTERVAL_IF_CLOSED = 60000; public static final String DOT_CLASS = PageTaskEdit.class.getName() + "."; private static final String OPERATION_LOAD_TASK = DOT_CLASS + "loadTask"; static final String OPERATION_SAVE_TASK = DOT_CLASS + "saveTask"; static final String OPERATION_DELETE_SYNC_TOKEN = DOT_CLASS + "deleteSyncToken"; public static final String ID_SUMMARY_PANEL = "summaryPanel"; public static final String ID_MAIN_PANEL = "mainPanel"; private static final Trace LOGGER = TraceManager.getTrace(PageTaskEdit.class); private String taskOid; private IModel<TaskDto> taskDtoModel; private LoadableModel<ObjectWrapper<TaskType>> objectWrapperModel; private boolean edit = false; private TaskDto currentTaskDto, previousTaskDto; private PageTaskController controller = new PageTaskController(this); private TaskMainPanel mainPanel; private IModel<AutoRefreshDto> refreshModel; private IModel<Boolean> showAdvancedFeaturesModel; public PageTaskEdit(PageParameters parameters) { taskOid = parameters.get(OnePageParameterEncoder.PARAMETER).toString(); taskDtoModel = new LoadableModel<TaskDto>(false) { @Override protected TaskDto load() { try { previousTaskDto = currentTaskDto; final OperationResult result = new OperationResult(OPERATION_LOAD_TASK); final Task operationTask = getTaskManager().createTaskInstance(OPERATION_LOAD_TASK); final TaskType taskType = loadTaskTypeChecked(taskOid, operationTask, result); currentTaskDto = prepareTaskDto(taskType, operationTask, result); return currentTaskDto; } catch (SchemaException|ObjectNotFoundException e) { throw new SystemException("Couldn't prepare task DTO: " + e.getMessage(), e); } } }; objectWrapperModel = new LoadableModel<ObjectWrapper<TaskType>>() { @Override protected ObjectWrapper<TaskType> load() { return loadObjectWrapper(taskDtoModel.getObject().getTaskType().asPrismObject(), new OperationResult("loadObjectWrapper")); } }; showAdvancedFeaturesModel = new Model<>(false); // todo save setting in session edit = false; initLayout(); } @Override protected IModel<String> createPageTitleModel() { TaskDto taskDto = taskDtoModel != null ? taskDtoModel.getObject() : null; String suffix; if (taskDto != null && taskDto.isWorkflowParent()) { suffix = ".wfOperation"; } else if (taskDto != null && taskDto.isWorkflowChild()) { suffix = ".wfRequest"; } else { suffix = ""; } return createStringResource("PageTaskEdit.title" + suffix); } private TaskType loadTaskTypeChecked(String taskOid, Task operationTask, OperationResult result) { TaskType taskType = loadTaskType(taskOid, operationTask, result); if (!result.isSuccess()) { showResult(result); } if (taskType == null) { getSession().error(getString("pageTaskEdit.message.cantTaskDetails")); showResult(result, false); throw getRestartResponseException(PageTasks.class); } return taskType; } TaskType loadTaskType(String taskOid, Task operationTask, OperationResult result) { TaskType taskType = null; try { Collection<SelectorOptions<GetOperationOptions>> options = GetOperationOptions.retrieveItemsNamed( TaskType.F_SUBTASK, TaskType.F_NODE_AS_OBSERVED, TaskType.F_NEXT_RUN_START_TIMESTAMP, TaskType.F_NEXT_RETRY_TIMESTAMP, new ItemPath(TaskType.F_WORKFLOW_CONTEXT, WfContextType.F_WORK_ITEM)); options.addAll(GetOperationOptions.resolveItemsNamed( new ItemPath(TaskType.F_WORKFLOW_CONTEXT, WfContextType.F_REQUESTER_REF) )); taskType = getModelService().getObject(TaskType.class, taskOid, options, operationTask, result).asObjectable(); result.computeStatus(); } catch (Exception ex) { result.recordFatalError("Couldn't get task.", ex); } return taskType; } private TaskDto prepareTaskDto(TaskType task, Task operationTask, OperationResult result) throws SchemaException, ObjectNotFoundException { TaskDto taskDto = new TaskDto(task, getModelService(), getTaskService(), getModelInteractionService(), getTaskManager(), getWorkflowManager(), TaskDtoProviderOptions.fullOptions(), operationTask, result, this); return taskDto; } protected void initLayout() { refreshModel = new Model(new AutoRefreshDto()); refreshModel.getObject().setInterval(getRefreshInterval()); IModel<PrismObject<TaskType>> prismObjectModel = new AbstractReadOnlyModel<PrismObject<TaskType>>() { @Override public PrismObject<TaskType> getObject() { return objectWrapperModel.getObject().getObject(); } }; final TaskSummaryPanel summaryPanel = new TaskSummaryPanel(ID_SUMMARY_PANEL, prismObjectModel, refreshModel, this); summaryPanel.setOutputMarkupId(true); add(summaryPanel); mainPanel = new TaskMainPanel(ID_MAIN_PANEL, objectWrapperModel, taskDtoModel, showAdvancedFeaturesModel, this); mainPanel.setOutputMarkupId(true); add(mainPanel); summaryPanel.getRefreshPanel().startRefreshing(this, null); } @Override public int getRefreshInterval() { TaskDtoExecutionStatus exec = getTaskDto().getExecution(); if (exec == null) { return REFRESH_INTERVAL_IF_CLOSED; } switch (exec) { case RUNNABLE: case RUNNING: case RUNNING_OR_RUNNABLE: case SUSPENDING: return REFRESH_INTERVAL_IF_RUNNABLE; case SUSPENDED: return REFRESH_INTERVAL_IF_SUSPENDED; case WAITING: return REFRESH_INTERVAL_IF_WAITING; case CLOSED: return REFRESH_INTERVAL_IF_CLOSED; } return REFRESH_INTERVAL_IF_RUNNABLE; } public void refresh(AjaxRequestTarget target) { TaskTabsVisibility tabsVisibilityOld = new TaskTabsVisibility(); tabsVisibilityOld.computeAll(this); TaskButtonsVisibility buttonsVisibilityOld = new TaskButtonsVisibility(); buttonsVisibilityOld.computeAll(this); refreshTaskModels(); TaskTabsVisibility tabsVisibilityNew = new TaskTabsVisibility(); tabsVisibilityNew.computeAll(this); TaskButtonsVisibility buttonsVisibilityNew = new TaskButtonsVisibility(); buttonsVisibilityNew.computeAll(this); if (!buttonsVisibilityNew.equals(buttonsVisibilityOld)) { target.add(mainPanel.getButtonPanel()); } if (tabsVisibilityNew.equals(tabsVisibilityOld)) { // soft version for (Component component : mainPanel.getTabPanel()) { if (component instanceof TaskTabPanel) { for (Component c : ((TaskTabPanel) component).getComponentsToUpdate()) { target.add(c); } } } } else { // hard version target.add(mainPanel.getTabPanel()); } target.add(getSummaryPanel()); AutoRefreshDto refreshDto = refreshModel.getObject(); refreshDto.recordRefreshed(); if (isEdit() || !refreshDto.isEnabled()) { getRefreshPanel().stopRefreshing(this, target); } else { getRefreshPanel().startRefreshing(this, target); } } public TaskDto getCurrentTaskDto() { return currentTaskDto; } public TaskDto getPreviousTaskDto() { return previousTaskDto; } @Override public Component getRefreshingBehaviorParent() { return getRefreshPanel(); } public void refreshTaskModels() { TaskDto oldTaskDto = taskDtoModel.getObject(); if (oldTaskDto == null) { LOGGER.warn("Null or empty taskModel"); return; } TaskManager taskManager = getTaskManager(); OperationResult result = new OperationResult("refresh"); Task operationTask = taskManager.createTaskInstance("refresh"); try { LOGGER.debug("Refreshing task {}", oldTaskDto); TaskType taskType = loadTaskType(oldTaskDto.getOid(), operationTask, result); TaskDto newTaskDto = prepareTaskDto(taskType, operationTask, result); final ObjectWrapper<TaskType> newWrapper = loadObjectWrapper(taskType.asPrismObject(), result); previousTaskDto = currentTaskDto; currentTaskDto = newTaskDto; taskDtoModel.setObject(newTaskDto); objectWrapperModel.setObject(newWrapper); } catch (ObjectNotFoundException|SchemaException|RuntimeException e) { LoggingUtils.logUnexpectedException(LOGGER, "Couldn't refresh task {}", e, oldTaskDto); } } protected ObjectWrapper<TaskType> loadObjectWrapper(PrismObject<TaskType> object, OperationResult result) { ObjectWrapper<TaskType> wrapper; ObjectWrapperFactory owf = new ObjectWrapperFactory(this); try { object.revive(getPrismContext()); // just to be sure (after deserialization the context is missing in this object) wrapper = owf.createObjectWrapper("pageAdminFocus.focusDetails", null, object, ContainerStatus.MODIFYING); } catch (Exception ex) { result.recordFatalError("Couldn't get user.", ex); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't load user", ex); wrapper = owf.createObjectWrapper("pageAdminFocus.focusDetails", null, object, null, null, ContainerStatus.MODIFYING, false); } showResult(wrapper.getResult(), false); return wrapper; } public boolean isEdit() { return edit; } public void setEdit(boolean edit) { this.edit = edit; } public IModel<TaskDto> getTaskDtoModel() { return taskDtoModel; } public LoadableModel<ObjectWrapper<TaskType>> getObjectWrapperModel() { return objectWrapperModel; } public TaskDto getTaskDto() { return taskDtoModel.getObject(); } public PageTaskController getController() { return controller; } public TaskSummaryPanel getSummaryPanel() { return (TaskSummaryPanel) get(ID_SUMMARY_PANEL); } public AutoRefreshPanel getRefreshPanel() { return getSummaryPanel().getRefreshPanel(); } public boolean isShowAdvanced() { return showAdvancedFeaturesModel.getObject(); } public VisibleEnableBehaviour createVisibleIfEdit(final ItemPath itemPath) { return new VisibleEnableBehaviour() { @Override public boolean isVisible() { return isEdit() && isEditable(itemPath); } }; } public VisibleEnableBehaviour createEnabledIfEdit(final ItemPath itemPath) { return new VisibleEnableBehaviour() { @Override public boolean isEnabled() { return isEdit() && isEditable(itemPath); } }; } public VisibleEnableBehaviour createVisibleIfView(final ItemPath itemPath) { return new VisibleEnableBehaviour() { @Override public boolean isVisible() { return isReadable(itemPath) && (!isEdit() || !isEditable(itemPath)); } }; } public VisibleEnableBehaviour createVisibleIfAccessible(QName... names) { return createVisibleIfAccessible(ItemPath.asPathArray(names)); } public VisibleEnableBehaviour createVisibleIfAccessible(final ItemPath... itemPaths) { return new VisibleEnableBehaviour() { @Override public boolean isVisible() { for (ItemPath itemPath : itemPaths) { if (!isReadable(itemPath)) { return false; } } return true; } }; } protected boolean isEditable() { return isEditable(objectWrapperModel.getObject().getDefinition()); } private boolean isEditable(ItemDefinition<?> definition) { if (definition.canModify()) { return true; } else if (definition instanceof PrismContainerDefinition) { for (ItemDefinition<?> subdef : ((PrismContainerDefinition<?>) definition).getDefinitions()) { if (isEditable(subdef)) { return true; } } } return false; } protected boolean isEditable(QName name) { return isEditable(new ItemPath(name)); } protected boolean isEditable(ItemPath itemPath) { ItemDefinition<?> itemDefinition = objectWrapperModel.getObject().getDefinition().findItemDefinition(itemPath); if (itemDefinition != null) { return itemDefinition.canRead() && itemDefinition.canModify(); } else { return true; } } protected boolean isReadable(ItemPath itemPath) { ItemDefinition<?> itemDefinition = objectWrapperModel.getObject().getDefinition().findItemDefinition(itemPath); if (itemDefinition != null) { return itemDefinition.canRead(); } else { return true; } } public boolean isExtensionReadable(QName name) { return isReadable(new ItemPath(TaskType.F_EXTENSION, name)); } boolean isReadableSomeOf(QName... names) { for (QName name : names) { if (isReadable(new ItemPath(name))) { return true; } } return false; } public Form getForm() { return mainPanel.getMainForm(); } boolean canSuspend() { return isAuthorized(ModelAuthorizationAction.SUSPEND_TASK); } boolean canResume() { return isAuthorized(ModelAuthorizationAction.RESUME_TASK); } boolean canRunNow() { return isAuthorized(ModelAuthorizationAction.RUN_TASK_IMMEDIATELY); } boolean canStop() { return isAuthorized(ModelAuthorizationAction.STOP_APPROVAL_PROCESS_INSTANCE); } private boolean isAuthorized(ModelAuthorizationAction action) { try { return getSecurityEnforcer().isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, null, null, null, null) || getSecurityEnforcer().isAuthorized(action.getUrl(), null, taskDtoModel.getObject().getTaskType().asPrismObject(), null, null, null); } catch (SchemaException e) { LoggingUtils.logUnexpectedException(LOGGER, "Couldn't determine authorization for {}", e, action); return true; // it is only GUI thing } } }