/* * 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.GuiStyleConstants; import com.evolveum.midpoint.gui.api.model.LoadableModel; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.model.api.ModelPublicConstants; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.polystring.PolyStringNormalizer; import com.evolveum.midpoint.prism.query.*; import com.evolveum.midpoint.prism.query.builder.QueryBuilder; import com.evolveum.midpoint.prism.query.builder.S_AtomicFilterEntry; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; 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.security.api.AuthorizationConstants; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.task.api.TaskExecutionStatus; 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.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.application.Url; import com.evolveum.midpoint.web.component.AjaxButton; import com.evolveum.midpoint.web.component.AjaxSubmitButton; import com.evolveum.midpoint.web.component.DateLabelComponent; import com.evolveum.midpoint.web.component.data.BoxedTablePanel; import com.evolveum.midpoint.web.component.data.Table; import com.evolveum.midpoint.web.component.data.column.*; import com.evolveum.midpoint.web.component.input.StringChoiceRenderer; import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; 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.page.admin.server.dto.*; import com.evolveum.midpoint.web.session.TasksStorage; import com.evolveum.midpoint.web.session.UserProfileStorage; import com.evolveum.midpoint.web.util.ObjectTypeGuiDescriptor; import com.evolveum.midpoint.web.util.OnePageParameterEncoder; import com.evolveum.midpoint.web.util.TooltipBehavior; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DurationFormatUtils; import org.apache.wicket.AttributeModifier; import org.apache.wicket.Component; import org.apache.wicket.MarkupContainer; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.behavior.AttributeAppender; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.export.AbstractExportableColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.export.CSVDataExporter; import org.apache.wicket.extensions.markup.html.repeater.data.table.export.ExportToolbar; 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.link.AbstractLink; import org.apache.wicket.markup.html.link.ResourceLink; import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.markup.repeater.Item; 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.request.mapper.parameter.PageParameters; import org.apache.wicket.request.resource.ResourceStreamResource; import org.apache.wicket.util.resource.IResourceStream; import org.apache.wicket.util.string.StringValue; import javax.xml.namespace.QName; import java.util.*; /** * @author lazyman */ @PageDescriptor( urls = { @Url(mountUrl = "/admin/tasks", matchUrlForSecurity = "/admin/tasks") }, action = { @AuthorizationAction(actionUri = PageAdminTasks.AUTHORIZATION_TASKS_ALL, label = PageAdminTasks.AUTH_TASKS_ALL_LABEL, description = PageAdminTasks.AUTH_TASKS_ALL_DESCRIPTION), @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_UI_TASKS_URL, label = "PageTasks.auth.tasks.label", description = "PageTasks.auth.tasks.description")}) public class PageTasks extends PageAdminTasks implements Refreshable { private static final Trace LOGGER = TraceManager.getTrace(PageTasks.class); private static final String DOT_CLASS = PageTasks.class.getName() + "."; private static final String OPERATION_SUSPEND_TASKS = DOT_CLASS + "suspendTasks"; private static final String OPERATION_RESUME_TASKS = DOT_CLASS + "resumeTasks"; private static final String OPERATION_RESUME_TASK = DOT_CLASS + "resumeTask"; private static final String OPERATION_DELETE_TASKS = DOT_CLASS + "deleteTasks"; private static final String OPERATION_DELETE_ALL_CLOSED_TASKS = DOT_CLASS + "deleteAllClosedTasks"; private static final String OPERATION_SCHEDULE_TASKS = DOT_CLASS + "scheduleTasks"; private static final String OPERATION_DELETE_NODES = DOT_CLASS + "deleteNodes"; private static final String OPERATION_START_SCHEDULERS = DOT_CLASS + "startSchedulers"; private static final String OPERATION_STOP_SCHEDULERS_AND_TASKS = DOT_CLASS + "stopSchedulersAndTasks"; private static final String OPERATION_STOP_SCHEDULERS = DOT_CLASS + "stopSchedulers"; private static final String OPERATION_DEACTIVATE_SERVICE_THREADS = DOT_CLASS + "deactivateServiceThreads"; private static final String OPERATION_REACTIVATE_SERVICE_THREADS = DOT_CLASS + "reactivateServiceThreads"; private static final String OPERATION_SYNCHRONIZE_TASKS = DOT_CLASS + "synchronizeTasks"; private static final String OPERATION_SYNCHRONIZE_WORKFLOW_REQUESTS = DOT_CLASS + "synchronizeWorkflowRequests"; private static final String OPERATION_REFRESH_TASKS = DOT_CLASS + "refreshTasks"; private static final String ALL_CATEGORIES = ""; public static final long WAIT_FOR_TASK_STOP = 2000L; private static final String ID_REFRESH_PANEL = "refreshPanel"; private static final String ID_MAIN_FORM = "mainForm"; private static final String ID_SEARCH_FORM = "searchForm"; private static final String ID_STATE = "state"; private static final String ID_CATEGORY = "category"; private static final String ID_SHOW_SUBTASKS = "showSubtasks"; private static final String ID_TASK_TABLE = "taskTable"; private static final String ID_NODE_TABLE = "nodeTable"; private static final String ID_SEARCH_CLEAR = "searchClear"; private static final String ID_TABLE_HEADER = "tableHeader"; public static final String ID_SYNCHRONIZE_WORKFLOW_REQUESTS = "synchronizeWorkflowRequests"; public static final String SELECTED_CATEGORY = "category"; private static final int REFRESH_INTERVAL = 10000; // don't set too low to prevent refreshing open inline menus (TODO skip refresh if a menu is open) private IModel<TasksSearchDto> searchModel; private String searchText = ""; private IModel<AutoRefreshDto> refreshModel; private AutoRefreshPanel refreshPanel; public PageTasks() { this("", null); } public PageTasks(String searchText) { this(searchText, null); } public PageTasks(PageParameters parameters) { this("", parameters); } // TODO clean the mess with constructors public PageTasks(String searchText, PageParameters parameters) { if (parameters != null) { getPageParameters().overwriteWith(parameters); } this.searchText = searchText; searchModel = new LoadableModel<TasksSearchDto>(false) { @Override protected TasksSearchDto load() { return loadTasksSearchDto(); } }; refreshModel = new Model<>(new AutoRefreshDto(REFRESH_INTERVAL)); initLayout(); refreshPanel.startRefreshing(this, null); } private TasksSearchDto loadTasksSearchDto() { TasksStorage storage = getSessionStorage().getTasks(); TasksSearchDto dto = storage.getTasksSearch(); if (dto == null) { dto = new TasksSearchDto(); dto.setShowSubtasks(false); } if (getPageParameters() != null) { StringValue category = getPageParameters().get(SELECTED_CATEGORY); if (category != null && category.toString() != null && !category.toString().isEmpty()) { dto.setCategory(category.toString()); } } if (dto.getStatus() == null) { dto.setStatus(TaskDtoExecutionStatusFilter.ALL); } return dto; } private void initLayout() { refreshPanel = new AutoRefreshPanel(ID_REFRESH_PANEL, refreshModel, this, false); add(refreshPanel); Form mainForm = new Form(ID_MAIN_FORM); add(mainForm); List<IColumn<TaskDto, String>> taskColumns = initTaskColumns(); TaskDtoProviderOptions options = TaskDtoProviderOptions.minimalOptions(); options.setGetNextRunStartTime(true); options.setUseClusterInformation(true); options.setResolveObjectRef(true); TaskDtoProvider provider = new TaskDtoProvider(PageTasks.this, options) { @Override protected void saveProviderPaging(ObjectQuery query, ObjectPaging paging) { TasksStorage storage = getSessionStorage().getTasks(); storage.setPaging(paging); } @Override public TaskDto createTaskDto(PrismObject<TaskType> task, Task opTask, OperationResult result) throws SchemaException, ObjectNotFoundException { TaskDto dto = super.createTaskDto(task, opTask, result); addInlineMenuToTaskRow(dto); return dto; } }; provider.setQuery(createTaskQuery()); BoxedTablePanel<TaskDto> taskTable = new BoxedTablePanel(ID_TASK_TABLE, provider, taskColumns, UserProfileStorage.TableId.PAGE_TASKS_PANEL, (int) getItemsPerPage(UserProfileStorage.TableId.PAGE_TASKS_PANEL)) { @Override protected WebMarkupContainer createHeader(String headerId) { return new SearchFragment(headerId, ID_TABLE_HEADER, PageTasks.this, searchModel); } @Override protected WebMarkupContainer createButtonToolbar(String id) { String fileName = "TaskType_" + createStringResource("MainObjectListPanel.exportFileName").getString(); CSVDataExporter csvDataExporter = new CSVDataExporter(); ResourceStreamResource resource = (new ResourceStreamResource() { protected IResourceStream getResourceStream() { return new ExportToolbar.DataExportResourceStreamWriter(csvDataExporter, getTaskTable().getDataTable()); } }).setFileName(fileName + "." + csvDataExporter.getFileNameExtension()); AbstractLink exportDataLink = (new ResourceLink(id, resource)).setBody(csvDataExporter.getDataFormatNameModel()); exportDataLink.add(new AttributeAppender("class", " btn btn-primary btn-sm")); return exportDataLink; } }; taskTable.setOutputMarkupId(true); TasksStorage storage = getSessionStorage().getTasks(); taskTable.setCurrentPage(storage.getPaging()); mainForm.add(taskTable); List<IColumn<NodeDto, String>> nodeColumns = initNodeColumns(); BoxedTablePanel nodeTable = new BoxedTablePanel(ID_NODE_TABLE, new NodeDtoProvider(PageTasks.this) { @Override public NodeDto createNodeDto(PrismObject<NodeType> node) { NodeDto dto = super.createNodeDto(node); addInlineMenuToNodeRow(dto); return dto; } }, nodeColumns, UserProfileStorage.TableId.PAGE_TASKS_NODES_PANEL, (int) getItemsPerPage(UserProfileStorage.TableId.PAGE_TASKS_NODES_PANEL)); nodeTable.setOutputMarkupId(true); nodeTable.setShowPaging(false); mainForm.add(nodeTable); initDiagnosticButtons(); } @Override public void refresh(AjaxRequestTarget target) { refreshTasks(target); } @Override public Component getRefreshingBehaviorParent() { return refreshPanel; } @Override public int getRefreshInterval() { return REFRESH_INTERVAL; } private List<IColumn<NodeDto, String>> initNodeColumns() { List<IColumn<NodeDto, String>> columns = new ArrayList<>(); IColumn column = new CheckBoxHeaderColumn<>(); columns.add(column); column = new PropertyColumn<>(createStringResource("pageTasks.node.name"), "name", "name"); columns.add(column); columns.add(new EnumPropertyColumn<NodeDto>(createStringResource("pageTasks.node.executionStatus"), "executionStatus") { @Override protected String translate(Enum en) { return createStringResource(en).getString(); } }); columns.add(new PropertyColumn(createStringResource("pageTasks.node.managementPort"), "managementPort")); columns.add(new AbstractColumn<NodeDto, String>(createStringResource("pageTasks.node.lastCheckInTime")) { @Override public void populateItem(Item<ICellPopulator<NodeDto>> item, String componentId, final IModel<NodeDto> rowModel) { item.add(new Label(componentId, new AbstractReadOnlyModel<Object>() { @Override public Object getObject() { return createLastCheckInTime(rowModel); } })); } }); CheckBoxColumn check = new CheckBoxColumn(createStringResource("pageTasks.node.clustered"), "clustered"); check.setEnabled(false); columns.add(check); columns.add(new PropertyColumn(createStringResource("pageTasks.node.statusMessage"), "statusMessage")); IColumn<NodeDto, String> menuColumn = new InlineMenuButtonColumn<NodeDto>(createNodesInlineMenu(false), 2, PageTasks.this){ @Override protected int getHeaderNumberOfButtons() { return 2; } @Override protected List<InlineMenuItem> getHeaderMenuItems() { return createNodesInlineMenu(true); } }; columns.add(menuColumn); return columns; } private List<InlineMenuItem> createNodesInlineMenu(boolean isHeader) { List<InlineMenuItem> items = new ArrayList<>(); items.add(new InlineMenuItem(createStringResource("pageTasks.button.stopScheduler"), new Model<Boolean>(false), new Model<Boolean>(false), false, new ColumnMenuAction<NodeDto>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ stopSchedulersPerformed(target); } else { NodeDto rowDto = getRowModel().getObject(); stopSchedulersPerformed(target, rowDto); } } }, InlineMenuItem.TASKS_INLINE_MENU_ITEM_ID.NODE_STOP_SCHEDULER.getMenuItemId(), GuiStyleConstants.CLASS_STOP_MENU_ITEM, DoubleButtonColumn.BUTTON_COLOR_CLASS.INFO.toString()){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return PageTasks.this.isNodeShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = createStringResource("pageTasks.message.stopSchedulerAction").getString(); return PageTasks.this.getNodeConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); items.add(new InlineMenuItem(createStringResource("pageTasks.button.stopSchedulerAndTasks"), false, new ColumnMenuAction<NodeDto>() { @Override public void onClick(AjaxRequestTarget target) { stopSchedulersAndTasksPerformed(target, getRowModel() != null ? getRowModel().getObject() : null); } }){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return PageTasks.this.isNodeShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = createStringResource("pageTasks.message.stopSchedulerTasksAction").getString(); return PageTasks.this.getNodeConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); items.add(new InlineMenuItem(createStringResource("pageTasks.button.startScheduler"), new Model<Boolean>(false), new Model<Boolean>(false), false, new ColumnMenuAction<NodeDto>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ startSchedulersPerformed(target); } else { NodeDto rowDto = getRowModel().getObject(); startSchedulersPerformed(target, rowDto); } } }, InlineMenuItem.TASKS_INLINE_MENU_ITEM_ID.NODE_START.getMenuItemId(), GuiStyleConstants.CLASS_START_MENU_ITEM, DoubleButtonColumn.BUTTON_COLOR_CLASS.INFO.toString()){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return PageTasks.this.isNodeShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = createStringResource("pageTasks.message.startSchedulerAction").getString(); return PageTasks.this.getNodeConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); items.add(new InlineMenuItem(createStringResource("pageTasks.button.deleteNode"), false, new ColumnMenuAction<NodeDto>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ deleteNodesPerformed(target); } else { NodeDto rowDto = getRowModel().getObject(); deleteNodesPerformed(target, rowDto); } } }){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return PageTasks.this.isNodeShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = createStringResource("pageTasks.message.deleteAction").getString(); return PageTasks.this.getNodeConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); return items; } private List<IColumn<TaskDto, String>> initTaskColumns() { List<IColumn<TaskDto, String>> columns = new ArrayList<IColumn<TaskDto, String>>(); IColumn column = new CheckBoxHeaderColumn<>(); columns.add(column); column = createTaskNameColumn(this, "pageTasks.task.name"); columns.add(column); columns.add(createTaskCategoryColumn(this, "pageTasks.task.category")); columns.add(new IconColumn<TaskDto>(createStringResource("")) { @Override protected IModel<String> createIconModel(IModel<TaskDto> rowModel) { ObjectReferenceType ref = rowModel.getObject().getObjectRef(); if (ref == null || ref.getType() == null) { return Model.of(""); } ObjectTypeGuiDescriptor guiDescriptor = getObjectTypeDescriptor(ref.getType()); String icon = guiDescriptor != null ? guiDescriptor.getBlackIcon() : ObjectTypeGuiDescriptor.ERROR_ICON; return new Model<>(icon); } private ObjectTypeGuiDescriptor getObjectTypeDescriptor(QName type) { return ObjectTypeGuiDescriptor.getDescriptor(ObjectTypes.getObjectTypeFromTypeQName(type)); } @Override public void populateItem(Item<ICellPopulator<TaskDto>> item, String componentId, IModel<TaskDto> rowModel) { super.populateItem(item, componentId, rowModel); ObjectReferenceType ref = rowModel.getObject().getObjectRef(); if (ref != null && ref.getType() != null) { ObjectTypeGuiDescriptor guiDescriptor = getObjectTypeDescriptor(ref.getType()); if (guiDescriptor != null) { item.add(AttributeModifier.replace("title", createStringResource(guiDescriptor.getLocalizationKey()))); item.add(new TooltipBehavior()); } } } }); columns.add(new AbstractExportableColumn<TaskDto, String>(createStringResource("pageTasks.task.objectRef")) { @Override public void populateItem(Item<ICellPopulator<TaskDto>> item, String componentId, final IModel<TaskDto> rowModel) { item.add(new Label(componentId, new AbstractReadOnlyModel<Object>() { @Override public Object getObject() { return createObjectRef(rowModel); } })); } @Override public IModel<String> getDataModel(IModel<TaskDto> rowModel) { return Model.of(createObjectRef(rowModel)); } }); columns.add(createTaskExecutionStatusColumn(this, "pageTasks.task.execution")); columns.add(new PropertyColumn<TaskDto, String>(createStringResource("pageTasks.task.executingAt"), "executingAt")); columns.add(new AbstractExportableColumn<TaskDto, String>(createStringResource("pageTasks.task.progress")) { @Override public void populateItem(Item<ICellPopulator<TaskDto>> cellItem, String componentId, final IModel<TaskDto> rowModel) { cellItem.add(new Label(componentId, new AbstractReadOnlyModel<Object>() { @Override public Object getObject() { return createProgress(rowModel); } })); } @Override public IModel<String> getDataModel(IModel<TaskDto> rowModel) { return Model.of(createProgress(rowModel)); } }); columns.add(new AbstractExportableColumn<TaskDto, String>(createStringResource("pageTasks.task.currentRunTime")) { @Override public void populateItem(final Item<ICellPopulator<TaskDto>> item, final String componentId, final IModel<TaskDto> rowModel) { DateLabelComponent dateLabel = new DateLabelComponent(componentId, new AbstractReadOnlyModel<Date>() { @Override public Date getObject() { Date date = createCurrentRuntime(rowModel); TaskDto task = rowModel.getObject(); if (task.getRawExecutionStatus() == TaskExecutionStatus.CLOSED) { ((DateLabelComponent) item.get(componentId)).setBefore("closed at "); } else if (date != null){ ((DateLabelComponent) item.get(componentId)).setBefore(DurationFormatUtils.formatDurationWords(date.getTime(), true, true)); } return date; } }, DateLabelComponent.MEDIUM_MEDIUM_STYLE); item.add(dateLabel); } @Override public IModel<String> getDataModel(IModel<TaskDto> rowModel) { TaskDto task = rowModel.getObject(); Date date = createCurrentRuntime(rowModel); String displayValue = ""; if (date != null) { if (task.getRawExecutionStatus() == TaskExecutionStatus.CLOSED) { displayValue = "closed at " + WebComponentUtil.getLocalizedDate(date, DateLabelComponent.LONG_MEDIUM_STYLE); } else { displayValue = DurationFormatUtils.formatDurationWords(date.getTime(), true, true); } } return Model.of(displayValue); } }); columns.add(new AbstractExportableColumn<TaskDto, String>(createStringResource("pageTasks.task.scheduledToRunAgain")) { @Override public void populateItem(Item<ICellPopulator<TaskDto>> item, String componentId, final IModel<TaskDto> rowModel) { item.add(new Label(componentId, new AbstractReadOnlyModel<Object>() { @Override public Object getObject() { return createScheduledToRunAgain(rowModel); } })); } @Override public IModel<String> getDataModel(IModel<TaskDto> rowModel) { return Model.of(createScheduledToRunAgain(rowModel)); } }); columns.add(new IconColumn<TaskDto>(createStringResource("pageTasks.task.status")) { @Override protected IModel<String> createTitleModel(final IModel<TaskDto> rowModel) { return new AbstractReadOnlyModel<String>() { @Override public String getObject() { TaskDto dto = rowModel.getObject(); if (dto != null && dto.getStatus() != null) { return createStringResourceStatic(PageTasks.this, dto.getStatus()).getString(); } else { return createStringResourceStatic(PageTasks.this, OperationResultStatus.UNKNOWN).getString(); } } }; } @Override protected IModel<String> createIconModel(final IModel<TaskDto> rowModel) { return new AbstractReadOnlyModel<String>() { @Override public String getObject() { if (rowModel != null && rowModel.getObject() != null && rowModel.getObject().getStatus() != null) { return OperationResultStatusPresentationProperties.parseOperationalResultStatus(rowModel.getObject().getStatus().createStatusType()).getIcon() + " fa-lg"; } else return OperationResultStatusPresentationProperties.UNKNOWN.getIcon() + " fa-lg"; } }; } }); IColumn<TaskDto, String> menuColumn = new InlineMenuButtonColumn<TaskDto>(createTasksInlineMenu(false), 2, PageTasks.this){ @Override protected int getHeaderNumberOfButtons() { return 2; } @Override protected List<InlineMenuItem> getHeaderMenuItems() { return createTasksInlineMenu(true); } }; columns.add(menuColumn); return columns; } private List<InlineMenuItem> createTasksInlineMenu(boolean isHeader) { List<InlineMenuItem> items = new ArrayList<>(); items.add(new InlineMenuItem(createStringResource("pageTasks.button.suspendTask"), new Model<Boolean>(false), new Model<Boolean>(false), false, new ColumnMenuAction<TaskDto>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ suspendTasksPerformed(target); } else { TaskDto rowDto = getRowModel().getObject(); suspendTaskPerformed(target, rowDto); } } }, InlineMenuItem.TASKS_INLINE_MENU_ITEM_ID.SUSPEND.getMenuItemId(), GuiStyleConstants.CLASS_SUSPEND_MENU_ITEM, DoubleButtonColumn.BUTTON_COLOR_CLASS.INFO.toString()){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return PageTasks.this.isTaskShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = createStringResource("pageTasks.message.suspendAction").getString(); return PageTasks.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); items.add(new InlineMenuItem(createStringResource("pageTasks.button.resumeTask"), new Model<Boolean>(false), new Model<Boolean>(false), false, new ColumnMenuAction<TaskDto>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ resumeTasksPerformed(target); } else { TaskDto rowDto = getRowModel().getObject(); resumeTaskPerformed(target, rowDto); } } }, InlineMenuItem.TASKS_INLINE_MENU_ITEM_ID.RESUME.getMenuItemId(), GuiStyleConstants.CLASS_RESUME_MENU_ITEM, DoubleButtonColumn.BUTTON_COLOR_CLASS.INFO.toString()){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return PageTasks.this.isTaskShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = createStringResource("pageTasks.message.resumeAction").getString(); return PageTasks.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); items.add(new InlineMenuItem(createStringResource("pageTasks.button.scheduleTask"), false, new ColumnMenuAction<TaskDto>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ scheduleTasksPerformed(target); } else { TaskDto rowDto = getRowModel().getObject(); scheduleTaskPerformed(target, rowDto); } } }){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return PageTasks.this.isTaskShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = createStringResource("pageTasks.message.runNowAction").getString(); return PageTasks.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); items.add(new InlineMenuItem(createStringResource("pageTasks.button.deleteTask"), false, new ColumnMenuAction<TaskDto>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ deleteTaskConfirmedPerformed(target, null); } else { TaskDto rowDto = getRowModel().getObject(); deleteTaskConfirmedPerformed(target, rowDto); } } }){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return PageTasks.this.isTaskShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = createStringResource("pageTasks.message.deleteAction").getString(); return PageTasks.this.getTaskConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); if (isHeader) { items.add(new InlineMenuItem(createStringResource("pageTasks.button.deleteAllClosedTasks"), false, new ColumnMenuAction<TaskDto>() { @Override public void onClick(AjaxRequestTarget target) { deleteAllClosedTasksConfirmedPerformed(target); } }){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return true; } @Override public IModel<String> getConfirmationMessageModel(){ return createStringResource("pageTasks.message.deleteAllClosedTasksConfirm"); } }); } return items; } // used in SubtasksPanel as well public static IColumn createTaskNameColumn(final Component component, String label) { LinkColumn<TaskDto> column = new LinkColumn<TaskDto>(createStringResourceStatic(component, label), TaskDto.F_NAME, TaskDto.F_NAME) { @Override public void onClick(AjaxRequestTarget target, IModel<TaskDto> rowModel) { TaskDto task = rowModel.getObject(); taskDetailsPerformed(target, task.getOid()); } private void taskDetailsPerformed(AjaxRequestTarget target, String oid) { PageParameters parameters = new PageParameters(); parameters.add(OnePageParameterEncoder.PARAMETER, oid); PageBase page = (PageBase) component.getPage(); page.navigateToNext(PageTaskEdit.class, parameters); } @Override public boolean isEnabled(IModel<TaskDto> rowModel) { return super.isEnabled(rowModel) && rowModel.getObject().getOid() != null; } }; return column; } public static AbstractColumn<TaskDto, String> createTaskCategoryColumn(final Component component, String label) { return new AbstractExportableColumn<TaskDto, String>(createStringResourceStatic(component, label)) { @Override public void populateItem(Item<ICellPopulator<TaskDto>> item, String componentId, final IModel<TaskDto> rowModel) { item.add(new Label(componentId, WebComponentUtil.createCategoryNameModel(component, new PropertyModel<String>(rowModel, TaskDto.F_CATEGORY)))); } @Override public IModel<String> getDataModel(IModel<TaskDto> rowModel) { return WebComponentUtil.createCategoryNameModel(component, new PropertyModel<String>(rowModel, TaskDto.F_CATEGORY)); } }; } public static EnumPropertyColumn createTaskResultStatusColumn(final Component component, String label) { return new EnumPropertyColumn(createStringResourceStatic(component, label), "status") { @Override protected String translate(Enum en) { return createStringResourceStatic(component, en).getString(); } }; } public static EnumPropertyColumn<TaskDto> createTaskExecutionStatusColumn(final Component component, String label) { return new EnumPropertyColumn<TaskDto>(createStringResourceStatic(component, label), "execution") { @Override protected String translate(Enum en) { return createStringResourceStatic(component, en).getString(); } }; } // public static IColumn createTaskDetailColumn(final Component component, String label, boolean workflowsEnabled) { // // if (workflowsEnabled) { // // return new LinkColumn<TaskDto>(createStringResourceStatic(component, label), TaskDto.F_WORKFLOW_LAST_DETAILS) { // // @Override // public void onClick(AjaxRequestTarget target, IModel<TaskDto> rowModel) { // TaskDto task = rowModel.getObject(); // taskDetailsPerformed(target, task); // } // // // todo display a message if process instance cannot be found // private void taskDetailsPerformed(AjaxRequestTarget target, TaskDto task) { // if (task.getWorkflowProcessInstanceId() != null) { // PageParameters parameters = new PageParameters(); // parameters.add(OnePageParameterEncoder.PARAMETER, task.getWorkflowProcessInstanceId()); // component.setResponsePage(new PageProcessInstance(parameters, (PageBase) component.getPage())); // } // } // // }; // } else { // return new PropertyColumn(createStringResourceStatic(component, label), TaskDto.F_WORKFLOW_LAST_DETAILS); // } // } private String createObjectRef(IModel<TaskDto> taskModel) { TaskDto task = taskModel.getObject(); if (task.getObjectRef() == null) { return ""; } if (StringUtils.isNotEmpty(task.getObjectRefName())) { return task.getObjectRefName(); } else { return task.getObjectRef().getOid(); } } private String createScheduledToRunAgain(IModel<TaskDto> taskModel) { TaskDto task = taskModel.getObject(); boolean runnable = task.getRawExecutionStatus() == TaskExecutionStatus.RUNNABLE; Long scheduledAfter = task.getScheduledToStartAgain(); Long retryAfter = runnable ? task.getRetryAfter() : null; if (scheduledAfter == null) { if (retryAfter == null || retryAfter <= 0) { return ""; } } else if (scheduledAfter == TaskDto.NOW) { // TODO what about retryTime? return getString(runnable ? "pageTasks.now" : "pageTasks.nowForNotRunningTasks"); } else if (scheduledAfter == TaskDto.RUNS_CONTINUALLY) { // retryTime is probably null here return getString("pageTasks.runsContinually"); } else if (scheduledAfter == TaskDto.ALREADY_PASSED && retryAfter == null) { return getString(runnable ? "pageTasks.alreadyPassed" : "pageTasks.alreadyPassedForNotRunningTasks"); } long displayTime; boolean displayAsRetry; if (retryAfter != null && retryAfter > 0 && (scheduledAfter == null || scheduledAfter < 0 || retryAfter < scheduledAfter)) { displayTime = retryAfter; displayAsRetry = true; } else { displayTime = scheduledAfter; displayAsRetry = false; } String key; if (runnable) { key = displayAsRetry ? "pageTasks.retryIn" : "pageTasks.in"; } else { key = "pageTasks.inForNotRunningTasks"; } //todo i18n return PageBase.createStringResourceStatic(this, key, DurationFormatUtils.formatDurationWords(displayTime, true, true)).getString(); } private String createProgress(IModel<TaskDto> taskModel) { TaskDto task = taskModel.getObject(); if (task.getStalledSince() != null) { return getString("pageTasks.stalledSince", new Date(task.getStalledSince()).toLocaleString(), task.getProgressDescription()); } else { return task.getProgressDescription(); } } private Date createCurrentRuntime(IModel<TaskDto> taskModel) { TaskDto task = taskModel.getObject(); if (task.getRawExecutionStatus() == TaskExecutionStatus.CLOSED) { //todo i18n and proper date/time formatting Long time = task.getCompletionTimestamp(); if (time == null) { return null; } return new Date(time); } else { Long time = task.getCurrentRuntime(); if (time == null) { return null; } //todo i18n return null; } } private String createLastCheckInTime(IModel<NodeDto> nodeModel) { NodeDto node = nodeModel.getObject(); Long time = node.getLastCheckInTime(); if (time == null || time == 0) { return ""; } //todo i18n return DurationFormatUtils.formatDurationWords(System.currentTimeMillis() - time, true, true) + " ago"; } private void initDiagnosticButtons() { AjaxButton deactivate = new AjaxButton("deactivateServiceThreads", createStringResource("pageTasks.button.deactivateServiceThreads")) { @Override public void onClick(AjaxRequestTarget target) { deactivateServiceThreadsPerformed(target); } }; add(deactivate); AjaxButton reactivate = new AjaxButton("reactivateServiceThreads", createStringResource("pageTasks.button.reactivateServiceThreads")) { @Override public void onClick(AjaxRequestTarget target) { reactivateServiceThreadsPerformed(target); } }; add(reactivate); AjaxButton synchronize = new AjaxButton("synchronizeTasks", createStringResource("pageTasks.button.synchronizeTasks")) { @Override public void onClick(AjaxRequestTarget target) { synchronizeTasksPerformed(target); } }; add(synchronize); AjaxButton synchronizeWorkflowRequests = new AjaxButton(ID_SYNCHRONIZE_WORKFLOW_REQUESTS, createStringResource("pageTasks.button.synchronizeWorkflowRequests")) { @Override public void onClick(AjaxRequestTarget target) { synchronizeWorkflowRequestsPerformed(target); } }; add(synchronizeWorkflowRequests); // adding Refresh button AjaxButton refresh = new AjaxButton("refreshTasks", createStringResource("pageTasks.button.refreshTasks")) { @Override public void onClick(AjaxRequestTarget target) { refreshTasks(target); } }; add(refresh); } private Table getTaskTable() { return (Table) get(createComponentPath(ID_MAIN_FORM, ID_TASK_TABLE)); } private Table getNodeTable() { return (Table) get(createComponentPath(ID_MAIN_FORM, ID_NODE_TABLE)); } private boolean isSomeTaskSelected(List<TaskDto> tasks, AjaxRequestTarget target) { if (!tasks.isEmpty()) { return true; } warn(getString("pageTasks.message.noTaskSelected")); target.add(getFeedbackPanel()); return false; } private boolean isSomeNodeSelected(List<NodeDto> nodes, AjaxRequestTarget target) { if (!nodes.isEmpty()) { return true; } warn(getString("pageTasks.message.noNodeSelected")); target.add(getFeedbackPanel()); return false; } private void suspendTasksPerformed(AjaxRequestTarget target, List<String> oidList) { OperationResult result = new OperationResult(OPERATION_SUSPEND_TASKS); try { boolean suspended = getTaskService().suspendTasks(oidList, WAIT_FOR_TASK_STOP, result); result.computeStatus(); if (result.isSuccess()) { if (suspended) { result.recordStatus(OperationResultStatus.SUCCESS, "The task(s) have been successfully suspended."); } else { result.recordWarning("Task(s) 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(s)", e); } showResult(result); //refresh feedback and table refreshTables(target); } private void suspendTaskPerformed(AjaxRequestTarget target, TaskDto dto) { suspendTasksPerformed(target, Arrays.asList(dto.getOid())); } //region Task-level actions private void suspendTasksPerformed(AjaxRequestTarget target) { List<TaskDto> taskTypeList = WebComponentUtil.getSelectedData(getTaskTable()); if (!isSomeTaskSelected(taskTypeList, target)) { return; } suspendTasksPerformed(target, TaskDto.getOids(taskTypeList)); } private void resumeTasksPerformed(AjaxRequestTarget target, List<String> oids) { OperationResult result = new OperationResult(OPERATION_RESUME_TASKS); try { getTaskService().resumeTasks(oids, result); result.computeStatus(); if (result.isSuccess()) { result.recordStatus(OperationResultStatus.SUCCESS, "The task(s) have been successfully resumed."); } } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | RuntimeException e) { result.recordFatalError("Couldn't resume the task(s)", e); } showResult(result); //refresh feedback and table refreshTables(target); } private void resumeTaskPerformed(AjaxRequestTarget target, TaskDto dto) { resumeTasksPerformed(target, Arrays.asList(dto.getOid())); } private void resumeTasksPerformed(AjaxRequestTarget target) { List<TaskDto> taskDtoList = WebComponentUtil.getSelectedData(getTaskTable()); if (!isSomeTaskSelected(taskDtoList, target)) { return; } resumeTasksPerformed(target, TaskDto.getOids(taskDtoList)); } private void scheduleTasksPerformed(AjaxRequestTarget target, List<String> oids) { OperationResult result = new OperationResult(OPERATION_SCHEDULE_TASKS); try { getTaskService().scheduleTasksNow(oids, result); result.computeStatus(); if (result.isSuccess()) { result.recordStatus(OperationResultStatus.SUCCESS, "The task(s) have been successfully scheduled."); } } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | RuntimeException e) { result.recordFatalError("Couldn't schedule the task(s)", e); } showResult(result); //refresh feedback and table refreshTables(target); } private void scheduleTaskPerformed(AjaxRequestTarget target, TaskDto dto) { scheduleTasksPerformed(target, Arrays.asList(dto.getOid())); } private void scheduleTasksPerformed(AjaxRequestTarget target) { List<TaskDto> taskDtoList = WebComponentUtil.getSelectedData(getTaskTable()); if (!isSomeTaskSelected(taskDtoList, target)) { return; } scheduleTasksPerformed(target, TaskDto.getOids(taskDtoList)); } //endregion //region Node-level actions private void nodeDetailsPerformed(AjaxRequestTarget target, String oid) { } private void stopSchedulersAndTasksPerformed(AjaxRequestTarget target, List<String> identifiers) { OperationResult result = new OperationResult(OPERATION_STOP_SCHEDULERS_AND_TASKS); try { boolean suspended = getTaskService().stopSchedulersAndTasks(identifiers, WAIT_FOR_TASK_STOP, result); result.computeStatus(); if (result.isSuccess()) { if (suspended) { result.recordStatus(OperationResultStatus.SUCCESS, "Selected node scheduler(s) have been " + "successfully stopped, including tasks that were running on them."); } else { result.recordWarning("Selected node scheduler(s) have been successfully paused; however, " + "some of the tasks they were executing are still running on them. Please check " + "their completion using task list."); } } } catch (SecurityViolationException | ObjectNotFoundException | SchemaException | RuntimeException e) { result.recordFatalError("Couldn't stop schedulers due", e); } showResult(result); //refresh feedback and table refreshTables(target); } private void stopSchedulersAndTasksPerformed(AjaxRequestTarget target, NodeDto dto) { List<NodeDto> nodeDtoList = new ArrayList<>(); if (dto != null){ nodeDtoList.add(dto); } else { nodeDtoList.addAll(WebComponentUtil.getSelectedData(getNodeTable())); } if (!isSomeNodeSelected(nodeDtoList, target)) { return; } stopSchedulersAndTasksPerformed(target, NodeDto.getNodeIdentifiers(nodeDtoList)); } private void startSchedulersPerformed(AjaxRequestTarget target, List<String> identifiers) { OperationResult result = new OperationResult(OPERATION_START_SCHEDULERS); try { getTaskService().startSchedulers(identifiers, result); result.computeStatus(); if (result.isSuccess()) { result.recordStatus(OperationResultStatus.SUCCESS, "Selected node scheduler(s) have been successfully started."); } } catch (SecurityViolationException | ObjectNotFoundException | SchemaException | RuntimeException e) { result.recordFatalError("Couldn't start the scheduler(s)", e); } showResult(result); //refresh feedback and table refreshTables(target); } private void startSchedulersPerformed(AjaxRequestTarget target, NodeDto dto) { startSchedulersPerformed(target, Arrays.asList(dto.getNodeIdentifier())); } private void startSchedulersPerformed(AjaxRequestTarget target) { List<NodeDto> nodeDtoList = WebComponentUtil.getSelectedData(getNodeTable()); if (!isSomeNodeSelected(nodeDtoList, target)) { return; } startSchedulersPerformed(target, NodeDto.getNodeIdentifiers(nodeDtoList)); } private void stopSchedulersPerformed(AjaxRequestTarget target, List<String> identifiers) { OperationResult result = new OperationResult(OPERATION_STOP_SCHEDULERS); try { getTaskService().stopSchedulers(identifiers, result); result.computeStatus(); if (result.isSuccess()) { result.recordStatus(OperationResultStatus.SUCCESS, "Selected node scheduler(s) have been successfully stopped."); } } catch (SecurityViolationException | ObjectNotFoundException | SchemaException | RuntimeException e) { result.recordFatalError("Couldn't stop the scheduler(s)", e); } showResult(result); //refresh feedback and table refreshTables(target); } private void stopSchedulersPerformed(AjaxRequestTarget target, NodeDto dto) { stopSchedulersPerformed(target, Arrays.asList(dto.getNodeIdentifier())); } private void stopSchedulersPerformed(AjaxRequestTarget target) { List<NodeDto> nodeDtoList = WebComponentUtil.getSelectedData(getNodeTable()); if (!isSomeNodeSelected(nodeDtoList, target)) { return; } stopSchedulersPerformed(target, NodeDto.getNodeIdentifiers(nodeDtoList)); } private void deleteNodesPerformed(AjaxRequestTarget target, List<NodeDto> nodes) { OperationResult result = new OperationResult(OPERATION_DELETE_NODES); Task task = createSimpleTask(OPERATION_DELETE_NODES); for (NodeDto nodeDto : nodes) { Collection<ObjectDelta<? extends ObjectType>> deltas = new ArrayList<>(); deltas.add(ObjectDelta.createDeleteDelta(NodeType.class, nodeDto.getOid(), getPrismContext())); try { getModelService().executeChanges(deltas, null, task, result); } catch (Exception e) { // until java 7 we do it in this way result.recordFatalError("Couldn't delete the node " + nodeDto.getNodeIdentifier(), e); } } result.computeStatus(); if (result.isSuccess()) { result.recordStatus(OperationResultStatus.SUCCESS, "Selected node(s) have been successfully deleted."); } showResult(result); NodeDtoProvider provider = (NodeDtoProvider) getNodeTable().getDataTable().getDataProvider(); provider.clearCache(); //refresh feedback and table refreshTables(target); } private void deleteNodesPerformed(AjaxRequestTarget target, NodeDto dto) { deleteNodesPerformed(target, Arrays.asList(dto)); } private void deleteNodesPerformed(AjaxRequestTarget target) { List<NodeDto> nodeDtoList = WebComponentUtil.getSelectedData(getNodeTable()); if (!isSomeNodeSelected(nodeDtoList, target)) { return; } deleteNodesPerformed(target, nodeDtoList); } //endregion //region Diagnostics actions private void deactivateServiceThreadsPerformed(AjaxRequestTarget target) { OperationResult result = new OperationResult(OPERATION_DEACTIVATE_SERVICE_THREADS); try { boolean stopped = getTaskService().deactivateServiceThreads(WAIT_FOR_TASK_STOP, result); result.computeStatus(); if (result.isSuccess()) { if (stopped) { result.recordStatus(OperationResultStatus.SUCCESS, "Service threads on local node have been successfully deactivated."); } else { result.recordWarning("Deactivation of service threads on local node have been successfully requested; however, some of the tasks are still running. Please check their completion using task list."); } } } catch (RuntimeException | SchemaException | SecurityViolationException e) { result.recordFatalError("Couldn't deactivate service threads on this node", e); } showResult(result); //refresh feedback and table refreshTables(target); } private void reactivateServiceThreadsPerformed(AjaxRequestTarget target) { OperationResult result = new OperationResult(OPERATION_REACTIVATE_SERVICE_THREADS); try { getTaskService().reactivateServiceThreads(result); result.computeStatus(); if (result.isSuccess()) { result.recordStatus(OperationResultStatus.SUCCESS, "Service threads on local node have been successfully reactivated."); } } catch (RuntimeException | SchemaException | SecurityViolationException e) { result.recordFatalError("Couldn't reactivate service threads on local node", e); } showResult(result); //refresh feedback and table refreshTables(target); } private void refreshTables(AjaxRequestTarget target) { target.add(getFeedbackPanel()); target.add((Component) getTaskTable()); target.add((Component) getNodeTable()); } private void synchronizeTasksPerformed(AjaxRequestTarget target) { OperationResult result = new OperationResult(OPERATION_SYNCHRONIZE_TASKS); try { getTaskService().synchronizeTasks(result); result.computeStatus(); if (result.isSuccess()) { // brutal hack - the subresult's message contains statistics result.recordStatus(OperationResultStatus.SUCCESS, result.getLastSubresult().getMessage()); } } catch (RuntimeException | SchemaException | SecurityViolationException e) { result.recordFatalError("Couldn't synchronize tasks", e); } showResult(result); //refresh feedback and table refreshTables(target); } private void synchronizeWorkflowRequestsPerformed(AjaxRequestTarget target) { OperationResult result = new OperationResult(OPERATION_SYNCHRONIZE_WORKFLOW_REQUESTS); try { getTaskService().synchronizeWorkflowRequests(result); result.computeStatusIfUnknown(); if (result.isSuccess()) { // brutal hack - the subresult's message contains statistics result.recordStatus(OperationResultStatus.SUCCESS, result.getLastSubresult().getMessage()); } } catch (RuntimeException | SchemaException | SecurityViolationException e) { result.recordFatalError("Couldn't synchronize tasks", e); } showResult(result); //refresh feedback and table refreshTables(target); } //endregion private void refreshTasks(AjaxRequestTarget target) { // searchModel = new LoadableModel<TasksSearchDto>(false) { // // @Override // protected TasksSearchDto load() { // return loadTasksSearchDto(); // } // }; target.add(refreshPanel); //refresh feedback and table refreshTables(target); if (refreshModel.getObject().isEnabled()) { refreshPanel.startRefreshing(this, target); } } private void searchFilterPerformed(AjaxRequestTarget target) { TasksSearchDto dto = searchModel.getObject(); // ObjectQuery query = createTaskQuery(dto.getStatus(), dto.getCategory(), dto.isShowSubtasks()); ObjectQuery query = createTaskQuery(); Table panel = getTaskTable(); DataTable table = panel.getDataTable(); TaskDtoProvider provider = (TaskDtoProvider) table.getDataProvider(); provider.setQuery(query); table.setCurrentPage(0); TasksStorage storage = getSessionStorage().getTasks(); storage.setTasksSearch(dto); target.add(getFeedbackPanel()); target.add((Component) getTaskTable()); } private ObjectQuery createTaskQuery() { TasksSearchDto dto = searchModel.getObject(); TaskDtoExecutionStatusFilter status = dto.getStatus(); String category = dto.getCategory(); boolean showSubtasks = dto.isShowSubtasks(); S_AtomicFilterEntry q = QueryBuilder.queryFor(TaskType.class, getPrismContext()); if (status != null) { q = status.appendFilter(q); } if (category != null && !ALL_CATEGORIES.equals(category)) { q = q.item(TaskType.F_CATEGORY).eq(category).and(); } if (StringUtils.isNotBlank(searchText)) { PolyStringNormalizer normalizer = getPrismContext().getDefaultPolyStringNormalizer(); String normalizedString = normalizer.normalize(searchText); q = q.item(TaskType.F_NAME).containsPoly(normalizedString, normalizedString).matchingNorm().and(); searchText = ""; // ??? } if (!Boolean.TRUE.equals(showSubtasks)) { q = q.item(TaskType.F_PARENT).isNull().and(); } return q.all().build(); } private void clearSearchPerformed(AjaxRequestTarget target) { TasksSearchDto tasksSearchDto = new TasksSearchDto(); tasksSearchDto.setCategory(ALL_CATEGORIES); tasksSearchDto.setStatus(TaskDtoExecutionStatusFilter.ALL); searchModel.setObject(tasksSearchDto); Table panel = getTaskTable(); DataTable table = panel.getDataTable(); TaskDtoProvider provider = (TaskDtoProvider) table.getDataProvider(); provider.setQuery(null); TasksStorage storage = getSessionStorage().getTasks(); storage.setTasksSearch(searchModel.getObject()); panel.setCurrentPage(storage.getPaging()); target.add((Component) panel); } private void deleteTaskConfirmedPerformed(AjaxRequestTarget target, TaskDto task) { List<TaskDto> taskDtoList = new ArrayList<>(); if (task != null){ taskDtoList.add(task); } else { taskDtoList.addAll(WebComponentUtil.getSelectedData(getTaskTable())); } if (!isSomeTaskSelected(taskDtoList, target)) { return; } OperationResult result = new OperationResult(OPERATION_DELETE_TASKS); try { getTaskService().suspendAndDeleteTasks(TaskDto.getOids(taskDtoList), WAIT_FOR_TASK_STOP, true, result); result.computeStatus(); if (result.isSuccess()) { result.recordStatus(OperationResultStatus.SUCCESS, "The task(s) have been successfully deleted."); } } catch (ObjectNotFoundException | SchemaException | SecurityViolationException | RuntimeException e) { result.recordFatalError("Couldn't delete the task(s)", e); } showResult(result); TaskDtoProvider provider = (TaskDtoProvider) getTaskTable().getDataTable().getDataProvider(); provider.clearCache(); //refresh feedback and table refreshTables(target); } private static class SearchFragment extends Fragment { public SearchFragment(String id, String markupId, MarkupContainer markupProvider, IModel<TasksSearchDto> model) { super(id, markupId, markupProvider, model); initLayout(); } private void initLayout() { final Form searchForm = new Form(ID_SEARCH_FORM); add(searchForm); searchForm.setOutputMarkupId(true); final IModel<TasksSearchDto> searchModel = (IModel) getDefaultModel(); DropDownChoice listSelect = new DropDownChoice(ID_STATE, new PropertyModel(searchModel, TasksSearchDto.F_STATUS), new AbstractReadOnlyModel<List<TaskDtoExecutionStatusFilter>>() { @Override public List<TaskDtoExecutionStatusFilter> getObject() { return createTypeList(); } }, new EnumChoiceRenderer(this)); listSelect.add(createFilterAjaxBehaviour()); listSelect.setOutputMarkupId(true); listSelect.setNullValid(false); if (listSelect.getModel().getObject() == null) { listSelect.getModel().setObject(TaskDtoExecutionStatusFilter.ALL); } searchForm.add(listSelect); DropDownChoice categorySelect = new DropDownChoice(ID_CATEGORY, new PropertyModel(searchModel, TasksSearchDto.F_CATEGORY), new AbstractReadOnlyModel<List<String>>() { @Override public List<String> getObject() { return createCategoryList(); } }, new StringChoiceRenderer("pageTasks.category.") { @Override public String getDisplayValue(String object) { if (ALL_CATEGORIES.equals(object)) { object = "AllCategories"; } return getPage().getString("pageTasks.category." + object); } } ); categorySelect.setOutputMarkupId(true); categorySelect.setNullValid(false); categorySelect.add(createFilterAjaxBehaviour()); if (categorySelect.getModel().getObject() == null) { categorySelect.getModel().setObject(ALL_CATEGORIES); } searchForm.add(categorySelect); CheckBox showSubtasks = new CheckBox(ID_SHOW_SUBTASKS, new PropertyModel(searchModel, TasksSearchDto.F_SHOW_SUBTASKS)); showSubtasks.add(createFilterAjaxBehaviour()); searchForm.add(showSubtasks); AjaxSubmitButton clearButton = new AjaxSubmitButton(ID_SEARCH_CLEAR) { @Override protected void onSubmit(AjaxRequestTarget target, Form<?> form) { PageTasks page = (PageTasks) getPage(); page.clearSearchPerformed(target); } @Override protected void onError(AjaxRequestTarget target, Form<?> form) { PageTasks page = (PageTasks) getPage(); target.add(page.getFeedbackPanel()); } }; searchForm.add(clearButton); } private AjaxFormComponentUpdatingBehavior createFilterAjaxBehaviour() { return new AjaxFormComponentUpdatingBehavior("change") { @Override protected void onUpdate(AjaxRequestTarget target) { PageTasks page = (PageTasks) getPage(); page.searchFilterPerformed(target); } }; } private List<TaskDtoExecutionStatusFilter> createTypeList() { List<TaskDtoExecutionStatusFilter> list = new ArrayList<TaskDtoExecutionStatusFilter>(); Collections.addAll(list, TaskDtoExecutionStatusFilter.values()); return list; } private List<String> createCategoryList() { List<String> categories = new ArrayList<String>(); categories.add(ALL_CATEGORIES); PageTasks page = (PageTasks) getPage(); List<String> list = page.getTaskService().getAllTaskCategories(); if (list != null) { categories.addAll(list); Collections.sort(categories); } return categories; } } private void deleteAllClosedTasksConfirmedPerformed(AjaxRequestTarget target) { OperationResult launchResult = new OperationResult(OPERATION_DELETE_ALL_CLOSED_TASKS); Task task = createSimpleTask(OPERATION_DELETE_ALL_CLOSED_TASKS); task.setHandlerUri(ModelPublicConstants.CLEANUP_TASK_HANDLER_URI); task.setName("Closed tasks cleanup"); try { CleanupPolicyType policy = new CleanupPolicyType(); policy.setMaxAge(XmlTypeConverter.createDuration(0)); CleanupPoliciesType policies = new CleanupPoliciesType(); policies.setClosedTasks(policy); PrismProperty<CleanupPoliciesType> policiesProperty = getPrismContext().getSchemaRegistry() .findPropertyDefinitionByElementName(SchemaConstants.MODEL_EXTENSION_CLEANUP_POLICIES).instantiate(); policiesProperty.setRealValue(policies); task.setExtensionProperty(policiesProperty); } catch (SchemaException e) { LOGGER.error("Error dealing with schema (task {})", task, e); launchResult.recordFatalError("Error dealing with schema", e); throw new IllegalStateException("Error dealing with schema", e); } getTaskManager().switchToBackground(task, launchResult); launchResult.setBackgroundTaskOid(task.getOid()); showResult(launchResult); target.add(getFeedbackPanel()); } private void addInlineMenuToTaskRow(TaskDto dto) { addInlineMenuToTaskDto(dto); List<TaskDto> list = new ArrayList<>(); if (dto.getSubtasks() != null) { list.addAll(dto.getTransientSubtasks()); } if (dto.getTransientSubtasks() != null) { list.addAll(dto.getSubtasks()); } for (TaskDto task : list) { addInlineMenuToTaskDto(task); } } private void addInlineMenuToTaskDto(final TaskDto dto) { List<InlineMenuItem> items = dto.getMenuItems(); if (!items.isEmpty()) { //menu was already added return; } items.addAll(createTasksInlineMenu(false)); } private void addInlineMenuToNodeRow(final NodeDto dto) { List<InlineMenuItem> items = dto.getMenuItems(); if (!items.isEmpty()) { //menu already added return; } items.addAll(createNodesInlineMenu(false)); } private IModel<String> getTaskConfirmationMessageModel(ColumnMenuAction action, String actionName){ if (action.getRowModel() == null) { return createStringResource("pageTasks.message.confirmationMessageForMultipleTaskObject", actionName, WebComponentUtil.getSelectedData(getTaskTable()).size()); } else { String objectName = ((TaskDto)(action.getRowModel().getObject())).getName(); return createStringResource("pageTasks.message.confirmationMessageForSingleTaskObject", actionName, objectName); } } private boolean isTaskShowConfirmationDialog(ColumnMenuAction action){ return action.getRowModel() != null || WebComponentUtil.getSelectedData(getTaskTable()).size() > 0; } private IModel<String> getNodeConfirmationMessageModel(ColumnMenuAction action, String actionName){ if (action.getRowModel() == null) { return createStringResource("pageTasks.message.confirmationMessageForMultipleNodeObject", actionName, WebComponentUtil.getSelectedData(getNodeTable()).size()); } else { String objectName = ((NodeDto)(action.getRowModel().getObject())).getName(); return createStringResource("pageTasks.message.confirmationMessageForSingleNodeObject", actionName, objectName); } } private boolean isNodeShowConfirmationDialog(ColumnMenuAction action){ return action.getRowModel() != null || WebComponentUtil.getSelectedData(getNodeTable()).size() > 0; } }