/* * 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.assignment; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.xml.namespace.QName; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.web.component.objectdetails.AbstractObjectMainPanel; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox; import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; 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 com.evolveum.midpoint.gui.api.GuiStyleConstants; import com.evolveum.midpoint.gui.api.component.BasePanel; import com.evolveum.midpoint.gui.api.component.TypedAssignablePanel; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismValue; import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.util.exception.SchemaException; 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.dialog.ConfirmationPanel; import com.evolveum.midpoint.web.component.dialog.Popupable; import com.evolveum.midpoint.web.component.menu.cog.InlineMenu; import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItemAction; import com.evolveum.midpoint.web.page.admin.orgs.OrgTreeAssignablePanel; import com.evolveum.midpoint.web.page.admin.users.dto.UserDtoStatus; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConstructionType; 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.OrgType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import org.w3c.dom.Attr; /** * @author shood */ public class AssignmentTablePanel<T extends ObjectType> extends BasePanel<List<AssignmentEditorDto>> { private static final long serialVersionUID = 1L; private static final Trace LOGGER = TraceManager.getTrace(AssignmentTablePanel.class); private static final String DOT_CLASS = AssignmentTablePanel.class.getName() + "."; private static final String ID_ASSIGNMENTS = "assignments"; private static final String ID_CHECK_ALL = "assignmentsCheckAll"; private static final String ID_HEADER = "assignmentsHeader"; private static final String ID_MENU = "assignmentsMenu"; private static final String ID_LIST = "assignmentList"; protected static final String ID_ROW = "assignmentEditor"; private PageBase pageBase = null; private boolean isModelChanged = false; public AssignmentTablePanel(String id, IModel<String> label, IModel<List<AssignmentEditorDto>> assignmentModel) { this(id, label, assignmentModel, null); } public AssignmentTablePanel(String id, IModel<String> label, IModel<List<AssignmentEditorDto>> assignmentModel, PageBase pageBase) { super(id, assignmentModel); this.pageBase = pageBase; initLayout(label); } public List<AssignmentType> getAssignmentTypeList() { return null; } public String getExcludeOid() { return null; } protected IModel<List<AssignmentEditorDto>> getAssignmentModel() { return getModel(); } private void initLayout(IModel<String> labelText) { final WebMarkupContainer assignments = new WebMarkupContainer(ID_ASSIGNMENTS); assignments.setOutputMarkupId(true); add(assignments); Label label = new Label(ID_HEADER, labelText); assignments.add(label); InlineMenu assignmentMenu = new InlineMenu(ID_MENU, new Model((Serializable) createAssignmentMenu())); assignmentMenu.setVisible(getAssignmentMenuVisibility()); assignments.add(assignmentMenu); ListView<AssignmentEditorDto> list = new ListView<AssignmentEditorDto>(ID_LIST, getModel()) { private static final long serialVersionUID = 1L; @Override protected void populateItem(ListItem<AssignmentEditorDto> item) { AssignmentTablePanel.this.populateAssignmentDetailsPanel(item); } }; list.setOutputMarkupId(true); assignments.add(list); AjaxCheckBox checkAll = new AjaxCheckBox(ID_CHECK_ALL, new Model()) { @Override protected void onUpdate(AjaxRequestTarget target) { List<AssignmentEditorDto> assignmentEditors = getAssignmentModel().getObject(); for (AssignmentEditorDto dto : assignmentEditors) { dto.setSelected(this.getModelObject()); } target.add(assignments); } }; checkAll.add(new VisibleEnableBehaviour(){ @Override public boolean isVisible(){ int count = 0; for (AssignmentEditorDto dto : getModelObject()){ if (dto.isSimpleView()){ count++; } } if (count == getModelObject().size()){ return false; } else { return true; } } }); assignments.add(checkAll); } protected void populateAssignmentDetailsPanel(ListItem<AssignmentEditorDto> item){ AssignmentEditorPanel editor = new AssignmentEditorPanel(ID_ROW, item.getModel(), pageBase){ @Override protected boolean ignoreMandatoryAttributes(){ return AssignmentTablePanel.this.ignoreMandatoryAttributes(); } }; item.add(editor); editor.add(getClassModifier(item)); } protected AttributeModifier getClassModifier(ListItem<AssignmentEditorDto> item){ return AttributeModifier.append("class", new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { AssignmentEditorDto dto = item.getModel().getObject(); ObjectReferenceType targetRef = dto.getTargetRef(); if (targetRef != null && targetRef.getType() != null) { return WebComponentUtil.getBoxThinCssClasses(targetRef.getType()); } else { return GuiStyleConstants.CLASS_OBJECT_RESOURCE_BOX_THIN_CSS_CLASSES; } } }); } protected List<InlineMenuItem> createAssignmentMenu() { List<InlineMenuItem> items = new ArrayList<>(); InlineMenuItem item; if (WebComponentUtil.isAuthorized(AuthorizationConstants.AUTZ_UI_ASSIGN_ACTION_URL)) { item = new InlineMenuItem(createStringResource("AssignmentTablePanel.menu.assign"), new InlineMenuItemAction() { private static final long serialVersionUID = 1L; @Override public void onClick(AjaxRequestTarget target) { TypedAssignablePanel panel = new TypedAssignablePanel( getPageBase().getMainPopupBodyId(), RoleType.class, true, getPageBase()) { private static final long serialVersionUID = 1L; @Override protected void addPerformed(AjaxRequestTarget target, List selected) { super.addPerformed(target, selected); addSelectedAssignablePerformed(target, selected, getPageBase().getMainPopup().getId()); reloadMainFormButtons(target); } }; panel.setOutputMarkupId(true); getPageBase().showMainPopup(panel, target); } }); items.add(item); item = new InlineMenuItem(createStringResource("AssignmentTablePanel.menu.assignOrg"), new InlineMenuItemAction() { private static final long serialVersionUID = 1L; @Override public void onClick(AjaxRequestTarget target) { int count = WebModelServiceUtils.countObjects(OrgType.class, null, getPageBase()); if (count > 0) { OrgTreeAssignablePanel orgTreePanel = new OrgTreeAssignablePanel( getPageBase().getMainPopupBodyId(), true, getPageBase()) { private static final long serialVersionUID = 1L; @Override protected void assignSelectedOrgPerformed(List<OrgType> selectedOrgs, AjaxRequestTarget target) { // TODO Auto-generated method stub addSelectedAssignablePerformed(target, (List) selectedOrgs, getPageBase().getMainPopup().getId()); reloadMainFormButtons(target); } }; orgTreePanel.setOutputMarkupId(true); getPageBase().showMainPopup(orgTreePanel, target); } else { warn(createStringResource("AssignmentTablePanel.menu.assignOrg.noorgs").getString()); target.add(getPageBase().getFeedbackPanel()); } } }); items.add(item); items.add(new InlineMenuItem()); } if (WebComponentUtil.isAuthorized(AuthorizationConstants.AUTZ_UI_UNASSIGN_ACTION_URL)) { item = new InlineMenuItem(createStringResource("AssignmentTablePanel.menu.unassign"), new InlineMenuItemAction() { private static final long serialVersionUID = 1L; @Override public void onClick(AjaxRequestTarget target) { AssignmentTablePanel.this.deleteAssignmentPerformed(target); } }); items.add(item); } item = new InlineMenuItem(createStringResource("AssignmentTablePanel.menu.showAllAssignments"), new InlineMenuItemAction() { private static final long serialVersionUID = 1L; @Override public void onClick(AjaxRequestTarget target) { showAllAssignments(target); } }); items.add(item); return items; } protected void showAllAssignments(AjaxRequestTarget target) { } private List<AssignmentEditorDto> getSelectedAssignments() { List<AssignmentEditorDto> selected = new ArrayList<>(); List<AssignmentEditorDto> all = getAssignmentModel().getObject(); for (AssignmentEditorDto dto : all) { if (dto.isSelected()) { selected.add(dto); } } return selected; } protected void deleteAssignmentPerformed(AjaxRequestTarget target) { List<AssignmentEditorDto> selected = getSelectedAssignments(); if (selected.isEmpty()) { warn(getNoAssignmentsSelectedMessage()); target.add(getPageBase().getFeedbackPanel()); return; } getPageBase().showMainPopup(getDeleteAssignmentPopupContent(), target); } protected String getNoAssignmentsSelectedMessage(){ return getString("AssignmentTablePanel.message.noAssignmentSelected"); } protected String getAssignmentsDeleteMessage(int size){ return createStringResource("AssignmentTablePanel.modal.message.delete", size).getString(); } private Popupable getDeleteAssignmentPopupContent() { return new ConfirmationPanel(getPageBase().getMainPopupBodyId(), new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { return getAssignmentsDeleteMessage(getSelectedAssignments().size()); } }) { private static final long serialVersionUID = 1L; @Override public void yesPerformed(AjaxRequestTarget target) { ModalWindow modalWindow = findParent(ModalWindow.class); if (modalWindow != null) { modalWindow.close(target); deleteAssignmentConfirmedPerformed(target, getSelectedAssignments()); reloadMainFormButtons(target); } } }; } private void deleteAssignmentConfirmedPerformed(AjaxRequestTarget target, List<AssignmentEditorDto> toDelete) { List<AssignmentEditorDto> assignments = getAssignmentModel().getObject(); for (AssignmentEditorDto assignment : toDelete) { if (UserDtoStatus.ADD.equals(assignment.getStatus())) { assignments.remove(assignment); } else { assignment.setStatus(UserDtoStatus.DELETE); assignment.setSelected(false); } } target.add(getPageBase().getFeedbackPanel(), get(ID_ASSIGNMENTS)); } protected void addSelectedAssignablePerformed(AjaxRequestTarget target, List<ObjectType> newAssignments, String popupId) { ModalWindow window = (ModalWindow) get(popupId); if (window != null) { window.close(target); } getPageBase().hideMainPopup(target); if (newAssignments.isEmpty()) { warn(getNoAssignmentsSelectedMessage()); target.add(getPageBase().getFeedbackPanel()); return; } List<AssignmentEditorDto> assignments = getAssignmentModel().getObject(); for (ObjectType object : newAssignments) { try { if (object instanceof ResourceType) { addSelectedResourceAssignPerformed((ResourceType) object); continue; } if (object instanceof UserType) { AssignmentEditorDto dto = AssignmentEditorDto.createDtoAddFromSelectedObject(object, SchemaConstants.ORG_DEPUTY, getPageBase()); assignments.add(dto); } else { AssignmentEditorDto dto = AssignmentEditorDto.createDtoAddFromSelectedObject(object, getPageBase()); assignments.add(dto); } } catch (Exception e) { error(getString("AssignmentTablePanel.message.couldntAssignObject", object.getName(), e.getMessage())); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't assign object", e); } } reloadAssignmentsPanel(target); } protected void reloadAssignmentsPanel(AjaxRequestTarget target){ target.add(getPageBase().getFeedbackPanel(), get(ID_ASSIGNMENTS)); } protected void addSelectedResourceAssignPerformed(ResourceType resource) { AssignmentType assignment = new AssignmentType(); ConstructionType construction = new ConstructionType(); assignment.setConstruction(construction); try { getPageBase().getPrismContext().adopt(assignment, UserType.class, new ItemPath(UserType.F_ASSIGNMENT)); } catch (SchemaException e) { error(getString("Could not create assignment", resource.getName(), e.getMessage())); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't create assignment", e); return; } construction.setResource(resource); List<AssignmentEditorDto> assignments = getAssignmentModel().getObject(); AssignmentEditorDto dto = new AssignmentEditorDto(UserDtoStatus.ADD, assignment, getPageBase()); assignments.add(dto); dto.setMinimized(true); dto.setShowEmpty(true); } public void handleAssignmentsWhenAdd(PrismObject<T> object, PrismContainerDefinition assignmentDef, List<AssignmentType> objectAssignments) throws SchemaException { List<AssignmentEditorDto> assignments = getAssignmentModel().getObject(); for (AssignmentEditorDto assDto : assignments) { if (!UserDtoStatus.ADD.equals(assDto.getStatus())) { warn(getString("AssignmentTablePanel.message.illegalAssignmentState", assDto.getStatus())); continue; } AssignmentType assignment = new AssignmentType(); PrismContainerValue value = assDto.getNewValue(getPageBase().getPrismContext()); assignment.setupContainerValue(value); value.applyDefinition(assignmentDef, false); objectAssignments.add(assignment.clone()); // todo remove this block [lazyman] after model is updated - it has // to remove resource from accountConstruction removeResourceFromAccConstruction(assignment); } } public ContainerDelta handleAssignmentDeltas(ObjectDelta<T> userDelta, PrismContainerDefinition def, QName assignmentPath) throws SchemaException { ContainerDelta assDelta = new ContainerDelta(new ItemPath(), assignmentPath, def, def.getPrismContext()); // hoping that def contains a prism // context! // PrismObject<OrgType> org = // (PrismObject<OrgType>)getModel().getObject().getAssignmentParent(); // PrismObjectDefinition orgDef = org.getDefinition(); // PrismContainerDefinition assignmentDef = // def.findContainerDefinition(assignmentPath); List<AssignmentEditorDto> assignments = getAssignmentModel().getObject(); for (AssignmentEditorDto assDto : assignments) { PrismContainerValue newValue = assDto.getNewValue(getPageBase().getPrismContext()); switch (assDto.getStatus()) { case ADD: newValue.applyDefinition(def, false); assDelta.addValueToAdd(newValue.clone()); break; case DELETE: PrismContainerValue oldValue = assDto.getOldValue(); oldValue.applyDefinition(def); assDelta.addValueToDelete(oldValue.clone()); break; case MODIFY: if (!assDto.isModified(getPageBase().getPrismContext())) { LOGGER.trace("Assignment '{}' not modified.", new Object[] { assDto.getName() }); continue; } handleModifyAssignmentDelta(assDto, def, newValue, userDelta); break; default: warn(getString("pageUser.message.illegalAssignmentState", assDto.getStatus())); } } if (!assDelta.isEmpty()) { assDelta = userDelta.addModification(assDelta); } // todo remove this block [lazyman] after model is updated - it has to // remove resource from accountConstruction Collection<PrismContainerValue> values = assDelta.getValues(PrismContainerValue.class); for (PrismContainerValue value : values) { AssignmentType ass = new AssignmentType(); ass.setupContainerValue(value); removeResourceFromAccConstruction(ass); } return assDelta; } private void handleModifyAssignmentDelta(AssignmentEditorDto assDto, PrismContainerDefinition assignmentDef, PrismContainerValue newValue, ObjectDelta<T> userDelta) throws SchemaException { LOGGER.debug("Handling modified assignment '{}', computing delta.", new Object[] { assDto.getName() }); PrismValue oldValue = assDto.getOldValue(); Collection<? extends ItemDelta> deltas = oldValue.diff(newValue); for (ItemDelta delta : deltas) { ItemPath deltaPath = delta.getPath().rest(); ItemDefinition deltaDef = assignmentDef.findItemDefinition(deltaPath); delta.setParentPath( WebComponentUtil.joinPath(oldValue.getPath(), delta.getPath().allExceptLast())); delta.applyDefinition(deltaDef); userDelta.addModification(delta); } } /** * remove this method after model is updated - it has to remove resource * from accountConstruction */ @Deprecated private void removeResourceFromAccConstruction(AssignmentType assignment) { ConstructionType accConstruction = assignment.getConstruction(); if (accConstruction == null || accConstruction.getResource() == null) { return; } ObjectReferenceType ref = new ObjectReferenceType(); ref.setOid(assignment.getConstruction().getResource().getOid()); ref.setType(ResourceType.COMPLEX_TYPE); assignment.getConstruction().setResourceRef(ref); assignment.getConstruction().setResource(null); } /** * Override to provide handle operation for partial error during provider * iterator operation. */ protected void handlePartialError(OperationResult result) { } protected boolean getAssignmentMenuVisibility(){ return true; } protected boolean ignoreMandatoryAttributes(){ return false; } protected void reloadMainFormButtons(AjaxRequestTarget target){ isModelChanged = true; AbstractObjectMainPanel panel = AssignmentTablePanel.this.findParent(AbstractObjectMainPanel.class); if (panel != null){ panel.reloadSavePreviewButtons(target); } } public boolean isModelChanged() { return isModelChanged; } }