/* * 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.component.util; import com.evolveum.midpoint.gui.api.GuiStyleConstants; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.CommonException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.data.column.ColumnMenuAction; import com.evolveum.midpoint.web.component.data.column.DoubleButtonColumn; import com.evolveum.midpoint.web.component.dialog.ConfirmationPanel; import com.evolveum.midpoint.web.component.dialog.Popupable; import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; import com.evolveum.midpoint.web.page.admin.configuration.component.HeaderMenuAction; import com.evolveum.midpoint.web.page.admin.users.PageUsers; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; 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.jetbrains.annotations.NotNull; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; /** * Provides common inline menu functionality for focal objects: enable, disable, reconcile, delete. * * TODO deduplicate this functionality with the one in PageUsers * * @author mederly */ public class FocusListInlineMenuHelper<F extends FocusType> implements Serializable { private static final long serialVersionUID = 1L; private static final Trace LOGGER = TraceManager.getTrace(FocusListInlineMenuHelper.class); // these are prefixed by parent page class name private static final String OPERATION_ENABLE_OBJECTS = "enableObjects"; private static final String OPERATION_DISABLE_OBJECTS = "disableObjects"; private static final String OPERATION_ENABLE_OBJECT = "enableObject"; private static final String OPERATION_DISABLE_OBJECT = "disableObject"; private static final String OPERATION_RECONCILE_OBJECTS = "reconcileObjects"; private static final String OPERATION_RECONCILE_OBJECT = "reconcileObject"; private static final String OPERATION_DELETE_OBJECTS = "deleteObjects"; private static final String OPERATION_DELETE_OBJECT = "deleteObject"; @NotNull private final Class<F> objectClass; @NotNull private final PageBase parentPage; @NotNull private final FocusListComponent<F> focusListComponent; private F singleDelete; public FocusListInlineMenuHelper(@NotNull Class<F> objectClass, @NotNull PageBase parentPage, @NotNull FocusListComponent<F> focusListComponent) { this.objectClass = objectClass; this.parentPage = parentPage; this.focusListComponent = focusListComponent; } public List<InlineMenuItem> createRowActions(boolean isHeader) { List<InlineMenuItem> menu = new ArrayList<>(); menu.add(new InlineMenuItem(parentPage.createStringResource("FocusListInlineMenuHelper.menu.enable"), new Model<Boolean>(false), new Model<Boolean>(false), false, new ColumnMenuAction<SelectableBean<F>>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ updateActivationPerformed(target, true, null); } else { SelectableBean<F> rowDto = getRowModel().getObject(); updateActivationPerformed(target, true, rowDto.getValue()); } } }, isHeader ? InlineMenuItem.FOCUS_LIST_INLINE_MENU_ITEM_ID.HEADER_ENABLE.getMenuItemId() : InlineMenuItem.FOCUS_LIST_INLINE_MENU_ITEM_ID.ENABLE.getMenuItemId(), GuiStyleConstants.CLASS_OBJECT_USER_ICON, DoubleButtonColumn.BUTTON_COLOR_CLASS.SUCCESS.toString()){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return FocusListInlineMenuHelper.this.isShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = parentPage.createStringResource("pageUsers.message.enableAction").getString(); return FocusListInlineMenuHelper.this.getConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); menu.add(new InlineMenuItem(parentPage.createStringResource("FocusListInlineMenuHelper.menu.disable"), isHeader ? new Model<Boolean>(true) : new Model<Boolean>(false), isHeader ? new Model<Boolean>(true) : new Model<Boolean>(false), false, new ColumnMenuAction<SelectableBean<F>>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ updateActivationPerformed(target, false, null); } else { SelectableBean<F> rowDto = getRowModel().getObject(); updateActivationPerformed(target, false, rowDto.getValue()); } } }, isHeader ? InlineMenuItem.FOCUS_LIST_INLINE_MENU_ITEM_ID.HEADER_DISABLE.getMenuItemId() : InlineMenuItem.FOCUS_LIST_INLINE_MENU_ITEM_ID.DISABLE.getMenuItemId(), GuiStyleConstants.CLASS_OBJECT_USER_ICON, DoubleButtonColumn.BUTTON_COLOR_CLASS.DANGER.toString()){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return FocusListInlineMenuHelper.this.isShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = parentPage.createStringResource("pageUsers.message.disableAction").getString(); return FocusListInlineMenuHelper.this.getConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); menu.add(new InlineMenuItem(parentPage.createStringResource("FocusListInlineMenuHelper.menu.reconcile"), new Model<Boolean>(false), new Model<Boolean>(false), false, new ColumnMenuAction<SelectableBean<F>>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ reconcilePerformed(target, null); } else { SelectableBean<F> rowDto = getRowModel().getObject(); reconcilePerformed(target, rowDto.getValue()); } } }, isHeader ? InlineMenuItem.FOCUS_LIST_INLINE_MENU_ITEM_ID.HEADER_RECONCILE.getMenuItemId() : InlineMenuItem.FOCUS_LIST_INLINE_MENU_ITEM_ID.RECONCILE.getMenuItemId(), GuiStyleConstants.CLASS_RECONCILE_MENU_ITEM, DoubleButtonColumn.BUTTON_COLOR_CLASS.INFO.toString()){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return FocusListInlineMenuHelper.this.isShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = parentPage.createStringResource("pageUsers.message.reconcileAction").getString(); return FocusListInlineMenuHelper.this.getConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); menu.add(new InlineMenuItem(parentPage.createStringResource("FocusListInlineMenuHelper.menu.delete"), new ColumnMenuAction<SelectableBean<F>>() { @Override public void onClick(AjaxRequestTarget target) { if (getRowModel() == null){ deleteConfirmedPerformed(target, null); } else { SelectableBean<F> rowDto = getRowModel().getObject(); deleteConfirmedPerformed(target, rowDto.getValue()); } } }){ private static final long serialVersionUID = 1L; @Override public boolean isShowConfirmationDialog() { return FocusListInlineMenuHelper.this.isShowConfirmationDialog((ColumnMenuAction) getAction()); } @Override public IModel<String> getConfirmationMessageModel(){ String actionName = parentPage.createStringResource("pageUsers.message.deleteAction").getString(); return FocusListInlineMenuHelper.this.getConfirmationMessageModel((ColumnMenuAction) getAction(), actionName); } }); return menu; } public void deleteConfirmedPerformed(AjaxRequestTarget target, F selectedObject) { List<F> objects = getObjectsToActOn(target, selectedObject); if (objects.isEmpty()) { return; } OperationResult result = new OperationResult(getOperationName(OPERATION_DELETE_OBJECTS)); for (F object : objects) { OperationResult subResult = result.createSubresult(getOperationName(OPERATION_DELETE_OBJECT)); try { Task task = parentPage.createSimpleTask(getOperationName(OPERATION_DELETE_OBJECT)); ObjectDelta delta = new ObjectDelta(objectClass, ChangeType.DELETE, parentPage.getPrismContext()); delta.setOid(object.getOid()); parentPage.getModelService().executeChanges(WebComponentUtil.createDeltaCollection(delta), null, task, subResult); subResult.computeStatus(); } catch (CommonException|RuntimeException ex) { subResult.recomputeStatus(); subResult.recordFatalError("Couldn't delete object.", ex); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't delete object", ex); } } result.computeStatusComposite(); focusListComponent.getObjectListPanel().clearCache(); parentPage.showResult(result); target.add(parentPage.getFeedbackPanel()); focusListComponent.getObjectListPanel().refreshTable(objectClass, target); focusListComponent.getObjectListPanel().clearCache(); } /** * This method updates object activation. If selectedObject parameter is not null, * than it updates only that objects, otherwise it checks table for selected * objects. */ private void updateActivationPerformed(AjaxRequestTarget target, boolean enabling, F selectedObject) { List<F> objects = getObjectsToActOn(target, selectedObject); if (objects.isEmpty()) { return; } OperationResult result = new OperationResult(getOperationName(enabling ? OPERATION_ENABLE_OBJECTS : OPERATION_DISABLE_OBJECTS)); for (F object : objects) { String operationName = getOperationName(enabling ? OPERATION_ENABLE_OBJECT : OPERATION_DISABLE_OBJECT); OperationResult subResult = result.createSubresult(operationName); try { Task task = parentPage.createSimpleTask(operationName); ObjectDelta objectDelta = WebModelServiceUtils.createActivationAdminStatusDelta( objectClass, object.getOid(), enabling, parentPage.getPrismContext()); parentPage.getModelService().executeChanges(WebComponentUtil.createDeltaCollection(objectDelta), null, task, subResult); subResult.recordSuccess(); } catch (CommonException|RuntimeException ex) { subResult.recomputeStatus(); if (enabling) { subResult.recordFatalError("Couldn't enable object.", ex); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't enable object", ex); } else { subResult.recordFatalError("Couldn't disable object.", ex); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't disable object", ex); } } } result.recomputeStatus(); parentPage.showResult(result); target.add(parentPage.getFeedbackPanel()); focusListComponent.getObjectListPanel().clearCache(); focusListComponent.getObjectListPanel().refreshTable(objectClass, target); } private void reconcilePerformed(AjaxRequestTarget target, F selectedObject) { List<F> objects = getObjectsToActOn(target, selectedObject); if (objects.isEmpty()) { return; } OperationResult result = new OperationResult(getOperationName(OPERATION_RECONCILE_OBJECTS)); for (F object : objects) { OperationResult opResult = result.createSubresult(getOperationName(OPERATION_RECONCILE_OBJECT)); try { Task task = parentPage.createSimpleTask(OPERATION_RECONCILE_OBJECT); ObjectDelta delta = ObjectDelta.createEmptyModifyDelta(objectClass, object.getOid(), parentPage.getPrismContext()); Collection<ObjectDelta<? extends ObjectType>> deltas = WebComponentUtil.createDeltaCollection(delta); parentPage.getModelService().executeChanges(deltas, ModelExecuteOptions.createReconcile(), task, opResult); opResult.computeStatusIfUnknown(); } catch (CommonException|RuntimeException ex) { opResult.recomputeStatus(); opResult.recordFatalError("Couldn't reconcile object " + object + ".", ex); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't reconcile object " + object + ".", ex); } } result.recomputeStatus(); parentPage.showResult(result); target.add(parentPage.getFeedbackPanel()); focusListComponent.getObjectListPanel().refreshTable(objectClass, target); focusListComponent.getObjectListPanel().clearCache(); } private String getOperationName(String suffix) { return parentPage.getClass().getName() + "." + suffix; } /** * This method check selection in table. If selectedObject != null than it * returns only this object. */ private List<F> getObjectsToActOn(AjaxRequestTarget target, F selectedObject) { if (selectedObject != null) { return Collections.singletonList(selectedObject); } else { List<F> objects; objects = focusListComponent.getObjectListPanel().getSelectedObjects(); if (objects.isEmpty()) { parentPage.warn(parentPage.getString("FocusListInlineMenuHelper.message.nothingSelected")); target.add(parentPage.getFeedbackPanel()); } return objects; } } protected boolean isShowConfirmationDialog(ColumnMenuAction action){ return false; } protected IModel<String> getConfirmationMessageModel(ColumnMenuAction action, String actionName){ return null; } }