diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/GuiStyleConstants.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/GuiStyleConstants.java index f6269fe3678..d998d804d60 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/GuiStyleConstants.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/GuiStyleConstants.java @@ -30,16 +30,19 @@ public class GuiStyleConstants { public static final String CLASS_OBJECT_USER_BOX_THIN_CSS_CLASSES = "object-user-box-thin"; public static final String CLASS_OBJECT_ROLE_ICON = "fa fa-street-view"; + public static final String CLASS_OBJECT_ROLE_BG = "object-role-bg"; public static final String CLASS_OBJECT_ROLE_ICON_COLORED = CLASS_OBJECT_ROLE_ICON + " object-role-color"; public static final String CLASS_OBJECT_ROLE_BOX_CSS_CLASSES = "object-role-box"; public static final String CLASS_OBJECT_ROLE_BOX_THIN_CSS_CLASSES = "object-role-box-thin"; public static final String CLASS_OBJECT_ORG_ICON = "fa fa-building"; + public static final String CLASS_OBJECT_ORG_BG = "object-org-bg"; public static final String CLASS_OBJECT_ORG_ICON_COLORED = CLASS_OBJECT_ORG_ICON + " object-org-color"; public static final String CLASS_OBJECT_ORG_BOX_CSS_CLASSES = "object-org-box"; public static final String CLASS_OBJECT_ORG_BOX_THIN_CSS_CLASSES = "object-org-box-thin"; public static final String CLASS_OBJECT_SERVICE_ICON = "fa fa-cloud"; + public static final String CLASS_OBJECT_SERVICE_BG = "object-service-bg"; public static final String CLASS_OBJECT_SERVICE_ICON_COLORED = CLASS_OBJECT_SERVICE_ICON + " object-service-color"; public static final String CLASS_OBJECT_SERVICE_BOX_CSS_CLASSES = "object-service-box"; public static final String CLASS_OBJECT_SERVICE_BOX_THIN_CSS_CLASSES = "object-service-box-thin"; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentCatalogPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentCatalogPanel.java index 2dab6e80cbd..ea2bd23afd2 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentCatalogPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentCatalogPanel.java @@ -17,18 +17,23 @@ import com.evolveum.midpoint.gui.api.component.BasePanel; import com.evolveum.midpoint.gui.api.page.PageBase; -import com.evolveum.midpoint.web.component.AjaxButton; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; import com.evolveum.midpoint.web.component.util.SelectableBean; -import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.page.admin.orgs.OrgTreePanel; +import com.evolveum.midpoint.web.page.self.dto.AssignmentViewType; import com.evolveum.midpoint.web.session.SessionStorage; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.apache.commons.lang.StringUtils; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.behavior.AttributeAppender; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import javax.xml.namespace.QName; @@ -46,7 +51,13 @@ public class AssignmentCatalogPanel extends BasePane private static String ID_CATALOG_ITEMS_PANEL_CONTAINER = "catalogItemsPanelContainer"; private static String ID_CATALOG_ITEMS_PANEL = "catalogItemsPanel"; + private static final String DOT_CLASS = AssignmentCatalogPanel.class.getName() + "."; + private static final String OPERATION_LOAD_ROLE_CATALOG_REFERENCE = DOT_CLASS + "loadRoleCatalogReference"; + private static final Trace LOGGER = TraceManager.getTrace(AssignmentCatalogPanel.class); + private PageBase pageBase; + private IModel rootOidModel; + private String rootOid; public AssignmentCatalogPanel(String id) { super(id); @@ -55,21 +66,32 @@ public AssignmentCatalogPanel(String id) { public AssignmentCatalogPanel(String id, String rootOid, PageBase pageBase) { super(id); this.pageBase = pageBase; - initLayout(null, rootOid); + this.rootOid = rootOid; + initLayout(); + } + + public AssignmentCatalogPanel(String id, PageBase pageBase) { + this(id, AssignmentViewType.getViewTypeFromSession(pageBase), pageBase); } - public AssignmentCatalogPanel(String id, QName viewTypeClass, PageBase pageBase) { + public AssignmentCatalogPanel(String id, AssignmentViewType viewType, PageBase pageBase) { super(id); this.pageBase = pageBase; - initLayout(viewTypeClass, null); + AssignmentViewType.saveViewTypeToSession(pageBase, viewType); + initLayout(); } - private void initLayout(QName viewTypeClass, final String rootOid) { + + private void initLayout() { + initModels(); setOutputMarkupId(true); + addOrReplaceLayout(); + } + public void addOrReplaceLayout(){ WebMarkupContainer treePanelContainer = new WebMarkupContainer(ID_TREE_PANEL_CONTAINER); treePanelContainer.setOutputMarkupId(true); - add(treePanelContainer); - if (rootOid != null) { + addOrReplace(treePanelContainer); + if (AssignmentViewType.ROLE_CATALOG_VIEW.equals(AssignmentViewType.getViewTypeFromSession(pageBase)) && StringUtils.isNotEmpty(rootOid)) { OrgTreePanel treePanel = new OrgTreePanel(ID_TREE_PANEL, new IModel() { @Override public String getObject() { @@ -106,38 +128,85 @@ protected List createTreeChildrenMenu() { }; treePanel.setOutputMarkupId(true); treePanelContainer.add(new AttributeAppender("class", "col-md-3")); - treePanelContainer.add(treePanel); + treePanelContainer.addOrReplace(treePanel); } else { WebMarkupContainer treePanel = new WebMarkupContainer(ID_TREE_PANEL); treePanel.setVisible(false); treePanel.setOutputMarkupId(true); - treePanelContainer.add(treePanel); + treePanelContainer.addOrReplace(treePanel); } WebMarkupContainer catalogItemsPanelContainer = new WebMarkupContainer(ID_CATALOG_ITEMS_PANEL_CONTAINER); catalogItemsPanelContainer.setOutputMarkupId(true); - add(catalogItemsPanelContainer); + addOrReplace(catalogItemsPanelContainer); - CatalogItemsPanel catalogItemsPanel; - if (rootOid != null) { - catalogItemsPanel = new CatalogItemsPanel(ID_CATALOG_ITEMS_PANEL, rootOid, pageBase); + CatalogItemsPanel catalogItemsPanel = new CatalogItemsPanel(ID_CATALOG_ITEMS_PANEL, rootOidModel, pageBase); + if (AssignmentViewType.ROLE_CATALOG_VIEW.equals(AssignmentViewType.getViewTypeFromSession(pageBase))) { catalogItemsPanelContainer.add(new AttributeAppender("class", "col-md-9")); } else { - catalogItemsPanel = new CatalogItemsPanel(ID_CATALOG_ITEMS_PANEL, viewTypeClass, pageBase); catalogItemsPanelContainer.add(new AttributeAppender("class", "col-md-12")); } catalogItemsPanel.setOutputMarkupId(true); - catalogItemsPanelContainer.add(catalogItemsPanel); + catalogItemsPanelContainer.addOrReplace(catalogItemsPanel); } private void selectTreeItemPerformed(SelectableBean selected, AjaxRequestTarget target) { final OrgType selectedOgr = selected.getValue(); - CatalogItemsPanel catalogItemsPanel = new CatalogItemsPanel(ID_CATALOG_ITEMS_PANEL, selectedOgr.getOid(), pageBase); + rootOidModel.setObject(selectedOgr.getOid()); + AssignmentViewType.saveViewTypeToSession(pageBase, AssignmentViewType.ROLE_CATALOG_VIEW); + CatalogItemsPanel catalogItemsPanel = new CatalogItemsPanel(ID_CATALOG_ITEMS_PANEL, rootOidModel, pageBase); catalogItemsPanel.setOutputMarkupId(true); ((WebMarkupContainer) get(ID_CATALOG_ITEMS_PANEL_CONTAINER)).addOrReplace(catalogItemsPanel); target.add(catalogItemsPanel); target.add(get(ID_CATALOG_ITEMS_PANEL_CONTAINER)); } + private void initModels(){ + rootOidModel = new IModel() { + @Override + public String getObject() { + return rootOid; + } + + @Override + public void setObject(String s) { + rootOid = s; + } + + @Override + public void detach() { + + } + }; + } + + public String getRootOid() { + return rootOid; + } + + public void setRootOid(String rootOid) { + this.rootOid = rootOid; + } + + private String getRoleCatalogOid() { + Task task = getPageBase().createAnonymousTask(OPERATION_LOAD_ROLE_CATALOG_REFERENCE); + OperationResult result = task.getResult(); + + PrismObject config; + try { + config = getPageBase().getModelService().getObject(SystemConfigurationType.class, + SystemObjectsType.SYSTEM_CONFIGURATION.value(), null, task, result); + } catch (ObjectNotFoundException | SchemaException | SecurityViolationException + | CommunicationException | ConfigurationException e) { + LOGGER.error("Error getting system configuration: {}", e.getMessage(), e); + return null; + } + if (config != null && config.asObjectable().getRoleManagement() != null && + config.asObjectable().getRoleManagement().getRoleCatalogRef() != null) { + return config.asObjectable().getRoleManagement().getRoleCatalogRef().getOid(); + } + return ""; + } + } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.html index 3d7bba44466..979aa0092b3 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.html @@ -17,16 +17,19 @@ xmlns:wicket="http://wicket.apache.org"> -
-
+
+ -
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentShoppingKart.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentShoppingKart.java index a2f344a1efc..fb6389acce8 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentShoppingKart.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentShoppingKart.java @@ -57,19 +57,16 @@ label = "PageAssignmentShoppingKart.auth.requestAssignment.label", description = "PageAssignmentShoppingKart.auth.requestAssignment.description")}) public class PageAssignmentShoppingKart extends PageSelf { - private static final long serialVersionUID = 1L; - + private static final long serialVersionUID = 1L; + private static final String ID_MAIN_PANEL = "mainPanel"; private static final String ID_MAIN_FORM = "mainForm"; - private static final String ID_VIEW_TYPE = "type"; - private static final String ID_BUTTON_PANEL = "buttonPanel"; private static final String DOT_CLASS = PageAssignmentShoppingKart.class.getName() + "."; private static final String OPERATION_LOAD_ROLE_CATALOG_REFERENCE = DOT_CLASS + "loadRoleCatalogReference"; private static final Trace LOGGER = TraceManager.getTrace(PageAssignmentShoppingKart.class); - private IModel viewModel; - private AssignmentViewType currentViewType = AssignmentViewType.ROLE_CATALOG_VIEW; private String catalogOid = null; + private boolean isFirstInit = true; public PageAssignmentShoppingKart() { initLayout(); @@ -80,24 +77,6 @@ private void initLayout() { add(mainForm); catalogOid = getRoleCatalogOid(); - viewModel = new IModel() { - @Override - public AssignmentViewType getObject() { - return currentViewType; - } - - @Override - public void setObject(AssignmentViewType assignmentViewType) { - currentViewType = assignmentViewType; - } - - @Override - public void detach() { - - } - }; - initButtonPanel(mainForm); - mainForm.add(initMainPanel()); } @@ -126,63 +105,28 @@ private String getRoleCatalogOid() { return ""; } - private void initButtonPanel(Form mainForm) { - WebMarkupContainer buttonPanel = new WebMarkupContainer(ID_BUTTON_PANEL); - buttonPanel.setOutputMarkupId(true); - mainForm.add(buttonPanel); - - DropDownChoice viewSelect = new DropDownChoice(ID_VIEW_TYPE, viewModel, new ListModel(createAssignableTypesList()), - new EnumChoiceRenderer(this)); - viewSelect.add(new OnChangeAjaxBehavior() { - - @Override - protected void onUpdate(AjaxRequestTarget target) { - QName viewTypeClass = getViewTypeClass(); - Component panel; - if (viewTypeClass != null) { - panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, viewTypeClass, PageAssignmentShoppingKart.this); + private Component initMainPanel() { + AssignmentViewType viewType = AssignmentViewType.getViewTypeFromSession(getPageBase()); + if (AssignmentViewType.ROLE_CATALOG_VIEW.equals(viewType)) { + if (StringUtils.isEmpty(catalogOid)) { + if (isFirstInit) { + isFirstInit = false; + AssignmentCatalogPanel panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, AssignmentViewType.ROLE_TYPE, PageAssignmentShoppingKart.this); panel.setOutputMarkupId(true); + return panel; } else { - panel = initMainPanel(); + Label panel = new Label(ID_MAIN_PANEL, createStringResource("PageAssignmentShoppingKart.roleCatalogIsNotConfigured")); + panel.setOutputMarkupId(true); + return panel; } - ((Form) PageAssignmentShoppingKart.this.get(ID_MAIN_FORM)).addOrReplace(panel); - target.add(get(ID_MAIN_FORM)); + } else { + AssignmentCatalogPanel panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, catalogOid, PageAssignmentShoppingKart.this); + panel.setOutputMarkupId(true); + return panel; } - }); - viewSelect.setOutputMarkupId(true); - buttonPanel.add(viewSelect); - - } - - public static List createAssignableTypesList() { - List focusTypeList = new ArrayList<>(); - - focusTypeList.add(AssignmentViewType.ROLE_CATALOG_VIEW); - focusTypeList.add(AssignmentViewType.ORG_TYPE); - focusTypeList.add(AssignmentViewType.ROLE_TYPE); - focusTypeList.add(AssignmentViewType.SERVICE_TYPE); - - return focusTypeList; - } - - private QName getViewTypeClass() { - if (AssignmentViewType.ORG_TYPE.equals(currentViewType)) { - return OrgType.COMPLEX_TYPE; - } else if (AssignmentViewType.ROLE_TYPE.equals(currentViewType)) { - return RoleType.COMPLEX_TYPE; - } else if (AssignmentViewType.SERVICE_TYPE.equals(currentViewType)) { - return ServiceType.COMPLEX_TYPE; - } - return null; - } - - private Component initMainPanel(){ - if (StringUtils.isEmpty(catalogOid)) { - Label panel = new Label(ID_MAIN_PANEL, createStringResource("PageAssignmentShoppingKart.roleCatalogIsNotConfigured")); - panel.setOutputMarkupId(true); - return panel; } else { - AssignmentCatalogPanel panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, catalogOid, PageAssignmentShoppingKart.this); + AssignmentCatalogPanel panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, PageAssignmentShoppingKart.this); + panel.setRootOid(catalogOid); panel.setOutputMarkupId(true); return panel; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.java index 8076174df7c..daee9fb09d7 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentsList.java @@ -62,7 +62,7 @@ private void initAssignmentsModel() { @Override public List getObject() { SessionStorage storage = getSessionStorage(); - return storage.getUsers().getAssignmentShoppingCart(); + return storage.getRoleCatalog().getAssignmentShoppingCart(); } @@ -110,7 +110,7 @@ protected void onError(AjaxRequestTarget target, org.apache.wicket.markup.html.f protected void onSubmit(AjaxRequestTarget target, org.apache.wicket.markup.html.form.Form form) { onRequestPerformed(target); SessionStorage storage = getSessionStorage(); - storage.getUsers().getAssignmentShoppingCart().clear(); + storage.getRoleCatalog().getAssignmentShoppingCart().clear(); } }; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/dto/AssignmentViewType.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/dto/AssignmentViewType.java index e9e5d140bd8..0168ba00cef 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/dto/AssignmentViewType.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/dto/AssignmentViewType.java @@ -16,9 +16,22 @@ package com.evolveum.midpoint.web.page.self.dto; +import com.evolveum.midpoint.gui.api.page.PageBase; +import com.evolveum.midpoint.web.session.SessionStorage; + /** * Created by honchar. */ public enum AssignmentViewType { ROLE_CATALOG_VIEW, ROLE_TYPE, ORG_TYPE, SERVICE_TYPE; + + public static AssignmentViewType getViewTypeFromSession(PageBase pageBase){ + SessionStorage storage = pageBase.getSessionStorage(); + return storage.getRoleCatalog().getViewType(); + } + + public static void saveViewTypeToSession(PageBase pageBase, AssignmentViewType viewType){ + SessionStorage storage = pageBase.getSessionStorage(); + storage.getRoleCatalog().setViewType(viewType); + } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RoleCatalogStorage.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RoleCatalogStorage.java new file mode 100644 index 00000000000..a8e568d7429 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RoleCatalogStorage.java @@ -0,0 +1,136 @@ +/* + * 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.session; + +import com.evolveum.midpoint.prism.query.ObjectPaging; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.web.component.assignment.AssignmentEditorDto; +import com.evolveum.midpoint.web.component.search.Search; +import com.evolveum.midpoint.web.component.util.SelectableBean; +import com.evolveum.midpoint.web.page.admin.users.dto.TreeStateSet; +import com.evolveum.midpoint.web.page.self.dto.AssignmentViewType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by honchar. + */ +public class RoleCatalogStorage implements PageStorage{ + /** + * DTO used for search in {@link com.evolveum.midpoint.web.page.self.PageAssignmentShoppingKart} + */ + private Search roleCatalogSearch; + + /** + * Paging DTO used in table on page {@link com.evolveum.midpoint.web.page.self.PageAssignmentShoppingKart} + */ + + private SelectableBean selectedItem; //selected tree item on the Org. structure page + private TreeStateSet> expandedItems; //expanded tree items on the Org. structure page + private int selectedTabId = 0; //selected tab id on the Org. structure page + private SelectableBean collapsedItem = null; //collapsed tree item + private List assignmentShoppingCart; // a list of assignments in the shopping cart + private AssignmentViewType viewType = AssignmentViewType.ROLE_CATALOG_VIEW; //the current view type + + private ObjectPaging roleCatalogPaging; + + public Search getSearch() { + return roleCatalogSearch; + } + + public void setSearch(Search roleCatalog) { + this.roleCatalogSearch = roleCatalog; + } + + @Override + public ObjectPaging getPaging() { + return roleCatalogPaging; + } + + @Override + public void setPaging(ObjectPaging roleCatalogPaging) { + this.roleCatalogPaging = roleCatalogPaging; + } + + @Override + public String debugDump() { + return debugDump(0); + } + + @Override + public String debugDump(int indent) { + StringBuilder sb = new StringBuilder(); + DebugUtil.indentDebugDump(sb, indent); + sb.append("RoleCatalogStorage\n"); + DebugUtil.debugDumpWithLabelLn(sb, "roleCatalogSearch", roleCatalogSearch, indent+1); + DebugUtil.debugDumpWithLabelLn(sb, "roleCatalogPaging", roleCatalogPaging, indent + 1); + return sb.toString(); + } + + public SelectableBean getSelectedItem() { + return selectedItem; + } + + public void setSelectedItem(SelectableBean selectedItem) { + this.selectedItem = selectedItem; + } + + public TreeStateSet> getExpandedItems() { + return expandedItems; + } + + public void setExpandedItems(TreeStateSet> expandedItems) { + this.expandedItems = expandedItems; + } + + public int getSelectedTabId() { + return selectedTabId; + } + + public void setSelectedTabId(int selectedTabId) { + this.selectedTabId = selectedTabId; + } + + public SelectableBean getCollapsedItem() { + return collapsedItem; + } + + public void setCollapsedItem(SelectableBean collapsedItem) { + this.collapsedItem = collapsedItem; + } + + + public List getAssignmentShoppingCart() { + return assignmentShoppingCart == null ? new ArrayList() : assignmentShoppingCart; + } + + public void setAssignmentShoppingCart(List assignmentShoppingCart) { + this.assignmentShoppingCart = assignmentShoppingCart; + } + + public AssignmentViewType getViewType() { + if (viewType == null){ + viewType = AssignmentViewType.ROLE_TYPE; + } + return viewType; + } + + public void setViewType(AssignmentViewType viewType) { + this.viewType = viewType; + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/SessionStorage.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/SessionStorage.java index a9df7684a89..f94234f2bb7 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/SessionStorage.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/SessionStorage.java @@ -45,6 +45,7 @@ public class SessionStorage implements Serializable, DebugDumpable { public static final String KEY_ROLES = "roles"; public static final String KEY_SERVICES = "services"; public static final String KEY_ROLE_MEMBERS = "roleMembers"; + public static final String KEY_ROLE_CATALOG = "roleMembers"; public static final String KEY_RESOURCE_ACCOUNT_CONTENT = "resourceAccountContent"; public static final String KEY_RESOURCE_ENTITLEMENT_CONTENT = "resourceEntitlementContent"; public static final String KEY_RESOURCE_GENERIC_CONTENT = "resourceGenericContent"; @@ -98,7 +99,14 @@ public RolesStorage getRoles() { return (RolesStorage)pageStorageMap.get(KEY_ROLES); } - + public RoleCatalogStorage getRoleCatalog() { + if (pageStorageMap.get(KEY_ROLE_CATALOG) == null) { + pageStorageMap.put(KEY_ROLE_CATALOG, new RoleCatalogStorage()); + } + return (RoleCatalogStorage)pageStorageMap.get(KEY_ROLE_CATALOG); + } + + public ServicesStorage getServices() { if (pageStorageMap.get(KEY_SERVICES) == null) { pageStorageMap.put(KEY_SERVICES, new ServicesStorage()); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/UsersStorage.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/UsersStorage.java index c5028c9ee36..5cf9785e82f 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/UsersStorage.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/UsersStorage.java @@ -60,8 +60,6 @@ public class UsersStorage implements PageStorage, DebugDumpable { */ private ObjectPaging usersPaging; - private List assignmentShoppingCart; - private SelectableBean selectedItem; //selected tree item on the Org. structure page private TreeStateSet> expandedItems; //expanded tree items on the Org. structure page private int selectedTabId = -1; //selected tab id on the Org. structure page @@ -135,14 +133,6 @@ public void setCollapsedItem(SelectableBean collapsedItem) { this.collapsedItem = collapsedItem; } - public List getAssignmentShoppingCart() { - return assignmentShoppingCart == null ? new ArrayList() : assignmentShoppingCart; - } - - public void setAssignmentShoppingCart(List assignmentShoppingCart) { - this.assignmentShoppingCart = assignmentShoppingCart; - } - @Override public String debugDump() { return debugDump(0); diff --git a/gui/admin-gui/src/main/resources/localization/Midpoint.properties b/gui/admin-gui/src/main/resources/localization/Midpoint.properties index 344f9111240..bdf63972891 100644 --- a/gui/admin-gui/src/main/resources/localization/Midpoint.properties +++ b/gui/admin-gui/src/main/resources/localization/Midpoint.properties @@ -3325,6 +3325,8 @@ PageAssignmentShoppingKart.title=Assignment request PageAssignmentShoppingKart.roleCatalogIsNotConfigured=Role catalog is not configured in the system configuration xml MultiButtonPanel.plusIconTitle=Add item to shopping cart MultiButtonPanel.assignmentDetailsPopupTitle=Assignment details +MultiButtonPanel.detailsLink=Details +MultiButtonPanel.addToCartLink=Add to cart PageAssignmentDetails.title=Assignment detail PageAssignmentDetails.backButton=Back PageAssignmentDetails.addToCartButton=Add to cart @@ -3339,13 +3341,18 @@ PageAssignmentsList.title=New assignments list PageAuditLogViewer.title=Audit Log Viewer PageAuditLogViewer.menuName=Audit Log Viewer PageAuditLogViewer.timeLabel=Time -PageAuditLogViewer.fromLabel=from -PageAuditLogViewer.toLabel=to -PageAuditLogViewer.initiatorLabel=initiator -PageAuditLogViewer.channelLabel=channel -PageAuditLogViewer.propertyLabel=property +PageAuditLogViewer.fromLabel=From +PageAuditLogViewer.toLabel=To +PageAuditLogViewer.initiatorNameLabel=Initiator name +PageAuditLogViewer.channelLabel=Channel +PageAuditLogViewer.hostIdentifierLabel=Host Identifier +PageAuditLogViewer.targetNameLabel=Target Name +PageAuditLogViewer.targetTypeLabel=Target Type +PageAuditLogViewer.targetOwnerNameLabel=Target Owner Name +PageAuditLogViewer.eventTypeLabel=Event Type +PageAuditLogViewer.eventStageLabel=Event Stage +PageAuditLogViewer.outcomeLabel=Outcome PageAuditLogViewer.column.time=Time -PageAuditLogViewer.column.initiatorRef=Initiator PageAuditLogViewer.column.taskIdentifier=Task Identifier PageAuditLogViewer.column.channel=Channel PageAuditLogViewer.column.delta=Delta diff --git a/gui/admin-gui/src/main/resources/localization/Midpoint_en.properties b/gui/admin-gui/src/main/resources/localization/Midpoint_en.properties index b8b6ae2a28a..cf4b5c44ed2 100644 --- a/gui/admin-gui/src/main/resources/localization/Midpoint_en.properties +++ b/gui/admin-gui/src/main/resources/localization/Midpoint_en.properties @@ -3285,6 +3285,8 @@ PageAssignmentShoppingKart.title=Assignment request PageAssignmentShoppingKart.roleCatalogIsNotConfigured=Role catalog is not configured in the system configuration xml MultiButtonPanel.plusIconTitle=Add item to shopping cart MultiButtonPanel.assignmentDetailsPopupTitle=Assignment details +MultiButtonPanel.detailsLink=Details +MultiButtonPanel.addToCartLink=Add to cart PageAssignmentDetails.title=Assignment detail PageAssignmentDetails.backButton=Back PageAssignmentDetails.addToCartButton=Add to cart @@ -3299,5 +3301,5 @@ PageAssignmentsList.title=New assignments list PageAuditLogViewer.title=Audit Log Viewer PageAuditLogViewer.menuName=Audit Log Viewer PageAuditLogViewer.timeLabel=Time -PageAuditLogViewer.fromLabel=from +PageAuditLogViewer.fromLabel=From PageAuditLogViewer.column.time=Time diff --git a/gui/admin-gui/src/main/webapp/less/midpoint-theme.less b/gui/admin-gui/src/main/webapp/less/midpoint-theme.less index 1f40442b9a0..317aa70371c 100644 --- a/gui/admin-gui/src/main/webapp/less/midpoint-theme.less +++ b/gui/admin-gui/src/main/webapp/less/midpoint-theme.less @@ -1086,10 +1086,26 @@ dd.stacktrace::before { // Shopping cart +.shopping-cart-item-table { + margin-top: 10px; + margin-left: 0px; + margin-right: 5px; + min-height: 460px; +} + .shopping-cart-item-box { .inner { - min-height: 90px; + min-height: 120px; + cursor: pointer; + } + + .inner-label { + font-size: 18px; + padding-top: 10px; + padding-left: 12px; + padding-right: 12px; + padding-bottom: 10px; } } @@ -1103,10 +1119,11 @@ dd.stacktrace::before { background: rgba(0, 0, 0, 0.1); .shopping-cart-item-button-details { - + cursor: pointer; } .shopping-cart-item-button-add { + cursor: pointer; float: right; } } \ No newline at end of file diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismValue.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismValue.java index 0275b824559..09af62ab801 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismValue.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismValue.java @@ -382,4 +382,16 @@ public static Set getRealValuesOfCollection(Collection boolean collectionContainsEquivalentValue(Collection collection, V value) { + if (collection == null) { + return false; + } + for (V collectionVal: collection) { + if (collectionVal.equals(value, true)) { + return true; + } + } + return false; + } } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/PrismAsserts.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/PrismAsserts.java index a185112ce6c..4055627d0e4 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/PrismAsserts.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/PrismAsserts.java @@ -417,18 +417,22 @@ public static void assertPropertyDelete(Collection modifica assertSet("delta "+propertyDelta+" for "+propertyPath.last(), "delete", propertyDelta.getValuesToDelete(), expectedValues); } - public static void assertNoItemDelta(ObjectDelta userDelta, ItemPath propertyPath) { - if (userDelta == null) { + public static void assertNoItemDelta(ObjectDelta objectDelta, QName itemName) { + assertNoItemDelta(objectDelta, new ItemPath(itemName)); + } + + public static void assertNoItemDelta(ObjectDelta objectDelta, ItemPath itemPath) { + if (objectDelta == null) { return; } - assert !userDelta.hasItemDelta(propertyPath) : "Delta for item "+propertyPath+" present while not expecting it"; + assert !objectDelta.hasItemDelta(itemPath) : "Delta for item "+itemPath+" present while not expecting it"; } - public static ContainerDelta assertContainerAdd(ObjectDelta objectDelta, QName name) { - return assertContainerAdd(objectDelta, new ItemPath(name)); + public static ContainerDelta assertContainerAddGetContainerDelta(ObjectDelta objectDelta, QName name) { + return assertContainerAddGetContainerDelta(objectDelta, new ItemPath(name)); } - public static ContainerDelta assertContainerAdd(ObjectDelta objectDelta, ItemPath propertyPath) { + public static ContainerDelta assertContainerAddGetContainerDelta(ObjectDelta objectDelta, ItemPath propertyPath) { ContainerDelta delta = objectDelta.findContainerDelta(propertyPath); assertNotNull("Container delta for "+propertyPath+" not found",delta); assert !delta.isEmpty() : "Container delta for "+propertyPath+" is empty"; @@ -437,11 +441,11 @@ public static ContainerDelta assertContainerAdd(ObjectDelta objectDelta, I return delta; } - public static ContainerDelta assertContainerDelete(ObjectDelta objectDelta, QName name) { - return assertContainerDelete(objectDelta, new ItemPath(name)); + public static ContainerDelta assertContainerDeleteGetContainerDelta(ObjectDelta objectDelta, QName name) { + return assertContainerDeleteGetContainerDelta(objectDelta, new ItemPath(name)); } - public static ContainerDelta assertContainerDelete(ObjectDelta objectDelta, ItemPath propertyPath) { + public static ContainerDelta assertContainerDeleteGetContainerDelta(ObjectDelta objectDelta, ItemPath propertyPath) { ContainerDelta delta = objectDelta.findContainerDelta(propertyPath); assertNotNull("Container delta for "+propertyPath+" not found",delta); assert !delta.isEmpty() : "Container delta for "+propertyPath+" is empty"; @@ -450,6 +454,48 @@ public static ContainerDelta assertContainerDelete(ObjectDelta objectDelta return delta; } + public static void assertContainerAdd(ObjectDelta objectDelta, QName itemName, C... containerables) { + assertContainerAdd(objectDelta, new ItemPath(itemName), containerables); + } + + public static void assertContainerAdd(ObjectDelta objectDelta, ItemPath propertyPath, C... containerables) { + List> expectedCVals = new ArrayList<>(); + for (C expectedContainerable: containerables) { + expectedCVals.add(expectedContainerable.asPrismContainerValue()); + } + } + + public static void assertContainerAdd(ObjectDelta objectDelta, QName itemName, + PrismContainerValue... expectedCVals) { + assertContainerAdd(objectDelta, new ItemPath(itemName), expectedCVals); + } + + public static void assertContainerAdd(ObjectDelta objectDelta, ItemPath propertyPath, + PrismContainerValue... expectedCVals) { + ContainerDelta delta = objectDelta.findContainerDelta(propertyPath); + assertNotNull("Container delta for "+propertyPath+" not found",delta); + assert !delta.isEmpty() : "Container delta for "+propertyPath+" is empty"; + assert delta.getValuesToAdd() != null : "Container delta for "+propertyPath+" has null values to add"; + assert !delta.getValuesToAdd().isEmpty() : "Container delta for "+propertyPath+" has empty values to add"; + assertEquivalentContainerValues("Wrong values in container delta for "+propertyPath, + delta.getValuesToAdd(), expectedCVals); + } + + private static void assertEquivalentContainerValues(String message, Collection> haveValues, + PrismContainerValue[] expectedCVals) { + List> expectedValues = Arrays.asList(expectedCVals); + Comparator> comparator = new Comparator>() { + @Override + public int compare(PrismContainerValue a, PrismContainerValue b) { + if (a.equivalent(b)) { + return 0; + } + return 1; + } + }; + assert MiscUtil.unorderedCollectionEquals(haveValues, expectedValues, comparator) : message; + } + public static void assertOrigin(ObjectDelta objectDelta, final OriginType... expectedOriginTypes) { assertOrigin(objectDelta, null, expectedOriginTypes); } diff --git a/infra/prism/src/test/java/com/evolveum/midpoint/prism/TestCompare.java b/infra/prism/src/test/java/com/evolveum/midpoint/prism/TestCompare.java index 4361169225f..54c09aa7856 100644 --- a/infra/prism/src/test/java/com/evolveum/midpoint/prism/TestCompare.java +++ b/infra/prism/src/test/java/com/evolveum/midpoint/prism/TestCompare.java @@ -156,7 +156,7 @@ public void testDiffJack() throws SchemaException, SAXException, IOException { new NameItemPathSegment(USER_DESCRIPTION_QNAME)), "Assignment II"); - ContainerDelta assignment3Delta = PrismAsserts.assertContainerAdd(jackDelta, new ItemPath(USER_ASSIGNMENT_QNAME)); + ContainerDelta assignment3Delta = PrismAsserts.assertContainerAddGetContainerDelta(jackDelta, new ItemPath(USER_ASSIGNMENT_QNAME)); PrismContainerValue assignment3DeltaAddValue = assignment3Delta.getValuesToAdd().iterator().next(); assertEquals("Assignment 3 wrong ID", USER_ASSIGNMENT_3_ID, assignment3DeltaAddValue.getId()); diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/ExpressionConstants.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/ExpressionConstants.java index ffcc1019d75..02ab0bda633 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/ExpressionConstants.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/ExpressionConstants.java @@ -65,6 +65,11 @@ public class ExpressionConstants { */ public static final QName VAR_ITERATION_TOKEN = new QName(SchemaConstants.NS_C, "iterationToken"); + // Variables used in object mergign expressions + public static final QName VAR_SIDE = new QName(SchemaConstants.NS_C, "side"); + public static final QName VAR_OBJECT_LEFT = new QName(SchemaConstants.NS_C, "objectLeft"); + public static final QName VAR_OBJECT_RIGHT = new QName(SchemaConstants.NS_C, "objectRight"); + public static final QName OUTPUT_ELMENT_NAME = new QName(SchemaConstants.NS_C, "output"); } diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/FocusTypeUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/FocusTypeUtil.java new file mode 100644 index 00000000000..37862763008 --- /dev/null +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/FocusTypeUtil.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 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.schema.util; + +import javax.xml.namespace.QName; + +import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; + +/** + * @author semancik + * + */ +public class FocusTypeUtil { + + public static AssignmentType createRoleAssignment(String roleOid) { + return createTargetAssignment(roleOid, RoleType.COMPLEX_TYPE); + } + + public static AssignmentType createOrgAssignment(String roleOid) { + return createTargetAssignment(roleOid, OrgType.COMPLEX_TYPE); + } + + public static AssignmentType createTargetAssignment(String targetOid, QName type) { + AssignmentType assignmentType = new AssignmentType(); + ObjectReferenceType targetRef = new ObjectReferenceType(); + targetRef.setOid(targetOid); + targetRef.setType(type); + assignmentType.setTargetRef(targetRef); + return assignmentType; + } +} diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index 026de5b24eb..c6582c622d3 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd @@ -9377,6 +9377,18 @@ + + + + + Configurations for object merging. E.g. for merging two users. + + + 3.5 + + + + @@ -12470,5 +12482,151 @@ + + + + + Configuration that specifies automatic merging of two objects. + + + + + + + + + + Short name of the merge cofiguration that also works as identifier for this configuration. + It has to be unique among all the applicable merge configurations. + + + + + + + Free form-name that can be displayed in user interfaces. + + + + + + + Free form description that can be displayed in user interfaces. It may be + longer text (more than few lines). + + + + + + + Item merge configuration. It will be applied to the specified (named) item. + + + + + + + Default merge configuration. It will be applied to all the items that are not + explicitly specified in the item merge configurations. + + + + + + + + + + TODO + + + + + + + + + + Strategy to process values from the left-hand-side object. + + + + + + + Strategy to process values from the right-hand-side object. + + + + + + + Expression to process every value (if specified by strategy). The value that the + expression returns will be taken. If the expression returns null then the value will + be skipped. + + + + + + + + + + TODO + + + + + + + + + + + + + + + + + + TODO + + + + + + + Ignore all the values. + + + + + + + + + + Take all the values. + + + + + + + + + + Take only values that are selected and processed by the expression. + + + + + + + + + diff --git a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseDiffPatch.java b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseDiffPatch.java index b66d98aefd1..034db4bdb15 100644 --- a/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseDiffPatch.java +++ b/infra/schema/src/test/java/com/evolveum/midpoint/schema/TestParseDiffPatch.java @@ -346,7 +346,7 @@ public void testTask() throws SchemaException, SAXException, IOException, JAXBEx Collection modifications = diffDelta.getModifications(); assertEquals("Unexpected number of modifications", 1, modifications.size()); // there is only one property in the container. after deleting this property, all container will be deleted, isn't it right? - PrismAsserts.assertContainerDelete(diffDelta, new ItemPath(TaskType.F_EXTENSION)); + PrismAsserts.assertContainerDeleteGetContainerDelta(diffDelta, new ItemPath(TaskType.F_EXTENSION)); // PrismAsserts.assertPropertyDelete(diffDelta, new ItemPath(TaskType.F_EXTENSION, // new QName("http://midpoint.evolveum.com/xml/ns/public/provisioning/liveSync-1.xsd","token")), 480); @@ -430,7 +430,7 @@ public void testResource() throws SchemaException, SAXException, IOException, JA assertEquals("Wrong change type", ChangeType.MODIFY, resourceDelta.getChangeType()); Collection modifications = resourceDelta.getModifications(); assertEquals("Unexpected number of modifications", 7, modifications.size()); - PrismAsserts.assertContainerDelete(resourceDelta, ResourceType.F_SCHEMA); + PrismAsserts.assertContainerDeleteGetContainerDelta(resourceDelta, ResourceType.F_SCHEMA); PrismAsserts.assertPropertyReplace(resourceDelta, pathTimeouts("update"), 3); PrismAsserts.assertPropertyReplace(resourceDelta, pathTimeouts("scriptOnResource"), 4); PrismAsserts.assertPropertyDelete(resourceDelta, diff --git a/infra/test-util/src/main/java/com/evolveum/midpoint/test/util/MidPointAsserts.java b/infra/test-util/src/main/java/com/evolveum/midpoint/test/util/MidPointAsserts.java index 4f9ae7015c3..267cb8d1c11 100644 --- a/infra/test-util/src/main/java/com/evolveum/midpoint/test/util/MidPointAsserts.java +++ b/infra/test-util/src/main/java/com/evolveum/midpoint/test/util/MidPointAsserts.java @@ -19,6 +19,7 @@ import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.assertNotNull; +import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -129,6 +130,28 @@ public static void assertAssignedRole(PrismObject user, public static void assertNotAssignedRole(PrismObject user, String roleOid) { assertNotAssigned(user, roleOid, RoleType.COMPLEX_TYPE); } + + public static void assertAssignedRoles(PrismObject user, String... roleOids) { + assertAssignedTargets(user, "roles", RoleType.COMPLEX_TYPE, roleOids); + } + + public static void assertAssignedOrgs(PrismObject user, String... orgOids) { + assertAssignedTargets(user, "orgs", OrgType.COMPLEX_TYPE, orgOids); + } + + public static void assertAssignedTargets(PrismObject user, String typeDesc, QName type, String... expectedTargetOids) { + F userType = user.asObjectable(); + List haveTagetOids = new ArrayList<>(); + for (AssignmentType assignmentType: userType.getAssignment()) { + ObjectReferenceType targetRef = assignmentType.getTargetRef(); + if (targetRef != null) { + if (type.equals(targetRef.getType())) { + haveTagetOids.add(targetRef.getOid()); + } + } + } + PrismAsserts.assertSets("Wrong "+typeDesc+" in "+user, haveTagetOids, expectedTargetOids); + } public static void assertNotAssignedResource(PrismObject user, String resourceOid) { F userType = user.asObjectable(); diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java index 0944f876d53..897ed0be611 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java @@ -56,6 +56,8 @@ public interface ModelInteractionService { static final String GET_CREDENTIALS_POLICY = CLASS_NAME_WITH_DOT + "getCredentialsPolicy"; static final String CHECK_PASSWORD = CLASS_NAME_WITH_DOT + "checkPassword"; static final String GET_CONNECTOR_OPERATIONAL_STATUS = CLASS_NAME_WITH_DOT + "getConnectorOperationalStatus"; + static final String MERGE_OBJECTS_PREVIEW_DELTA = CLASS_NAME_WITH_DOT + "mergeObjectsPreviewDelta"; + static final String MERGE_OBJECTS_PREVIEW_OBJECT = CLASS_NAME_WITH_DOT + "mergeObjectsPreviewObject"; /** * Computes the most likely changes triggered by the provided delta. The delta may be any change of any object, e.g. @@ -179,5 +181,13 @@ AccessCertificationConfigurationType getCertificationConfiguration(OperationResu ConnectorOperationalStatus getConnectorOperationalStatus(String resourceOid, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException; + + ObjectDelta mergeObjectsPreviewDelta(Class type, + String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException; + + PrismObject mergeObjectsPreviewObject(Class type, + String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException; } diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java index 9ff27b8f442..025f51f8493 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java @@ -107,6 +107,7 @@ public interface ModelService { static final String IMPORT_OBJECTS_FROM_STREAM = CLASS_NAME_WITH_DOT + "importObjectsFromStream"; static final String POST_INIT = CLASS_NAME_WITH_DOT + "postInit"; static final String DISCOVER_CONNECTORS = CLASS_NAME_WITH_DOT + "discoverConnectors"; + static final String MERGE_OBJECTS = CLASS_NAME_WITH_DOT + "mergeObjects"; static final String AUTZ_NAMESPACE = AuthorizationConstants.NS_AUTHORIZATION_MODEL; @@ -641,7 +642,7 @@ public Set discoverConnectors(ConnectorHostType hostType, Task ta * @param ignoreItemPaths * @param task * @param result - * @param + * @param * @return * @throws SchemaException * @throws ObjectNotFoundException @@ -649,9 +650,27 @@ public Set discoverConnectors(ConnectorHostType hostType, Task ta * @throws CommunicationException * @throws ConfigurationException */ - CompareResultType compareObject(PrismObject object, + CompareResultType compareObject(PrismObject object, Collection> readOptions, ModelCompareOptions compareOptions, @NotNull List ignoreItemPaths, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException; + + /** + * Merge two objects into one. + * + * EXPERIMENTAL feature. The method signature is likely to change in the future. + * + * @param type object type + * @param leftOid left-side object OID + * @param rightOid right-side object OID + * @param mergeConfigurationName name of the merge configuration to use + * @param task + * @param result + * @return + */ + Collection> mergeObjects(Class type, String leftOid, String rightOid, + String mergeConfigurationName, Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, ConfigurationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, PolicyViolationException, SecurityViolationException; + } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java index e052a3010cc..c205e5c449f 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java @@ -193,6 +193,9 @@ public class ModelController implements ModelService, TaskService, WorkflowServi @Autowired(required = true) private SchemaTransformer schemaTransformer; + @Autowired(required = true) + private ObjectMerger objectMerger; + @Autowired(required = true) private SystemObjectCache systemObjectCache; @@ -2092,4 +2095,39 @@ public AccessCertificationCampaignType createCampaign(String definitionOid, Task return getCertificationManagerChecked().createCampaign(definitionOid, task, parentResult); } //endregion + + @Override + public Collection> mergeObjects(Class type, + String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, ConfigurationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, PolicyViolationException, SecurityViolationException { + + OperationResult result = parentResult.createSubresult(MERGE_OBJECTS); + result.addParam("leftOid", leftOid); + result.addParam("rightOid", rightOid); + result.addParam("class", type); + + RepositoryCache.enter(); + + try { + + Collection> deltas = + objectMerger.mergeObjects(type, leftOid, rightOid, mergeConfigurationName, task, result); + + result.computeStatus(); + return deltas; + + } catch (ObjectNotFoundException | SchemaException | ConfigurationException + | ObjectAlreadyExistsException | ExpressionEvaluationException | CommunicationException + | PolicyViolationException | SecurityViolationException e) { + ModelUtils.recordFatalError(result, e); + throw e; + } catch (RuntimeException | Error e) { + ModelUtils.recordFatalError(result, e); + throw e; + } finally { + QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); + RepositoryCache.exit(); + } + + } } \ No newline at end of file diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java index 821f6102517..a040c62a9be 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java @@ -114,6 +114,9 @@ public class ModelInteractionServiceImpl implements ModelInteractionService { @Autowired(required = true) private ModelObjectResolver objectResolver; + + @Autowired(required = true) + private ObjectMerger objectMerger; @Autowired(required = true) @Qualifier("cacheRepositoryService") @@ -703,4 +706,51 @@ public ConnectorOperationalStatus getConnectorOperationalStatus(String resourceO return status; } + @Override + public ObjectDelta mergeObjectsPreviewDelta(Class type, String leftOid, + String rightOid, String mergeConfigurationName, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException { + OperationResult result = parentResult.createMinorSubresult(MERGE_OBJECTS_PREVIEW_DELTA); + + try { + + ObjectDelta objectDelta = objectMerger.computeMergeDelta(type, leftOid, rightOid, mergeConfigurationName, task, result); + + result.computeStatus(); + return objectDelta; + + } catch (ObjectNotFoundException | SchemaException | ConfigurationException | ExpressionEvaluationException | RuntimeException | Error e) { + result.recordFatalError(e); + throw e; + } + } + + @Override + public PrismObject mergeObjectsPreviewObject(Class type, String leftOid, + String rightOid, String mergeConfigurationName, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException { + OperationResult result = parentResult.createMinorSubresult(MERGE_OBJECTS_PREVIEW_OBJECT); + + try { + + ObjectDelta objectDelta = objectMerger.computeMergeDelta(type, leftOid, rightOid, mergeConfigurationName, task, result); + + final PrismObject objectLeft = objectResolver.getObjectSimple(type, leftOid, null, task, result).asPrismObject(); + + if (objectDelta == null) { + result.computeStatus(); + return objectLeft; + } + + objectDelta.applyTo(objectLeft); + + result.computeStatus(); + return objectLeft; + + } catch (ObjectNotFoundException | SchemaException | ConfigurationException | ExpressionEvaluationException | RuntimeException | Error e) { + result.recordFatalError(e); + throw e; + } + } + } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ObjectMerger.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ObjectMerger.java new file mode 100644 index 00000000000..b9bb70d8d32 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ObjectMerger.java @@ -0,0 +1,428 @@ +/** + * Copyright (c) 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.model.impl.controller; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.evolveum.midpoint.model.api.PolicyViolationException; +import com.evolveum.midpoint.model.common.SystemObjectCache; +import com.evolveum.midpoint.model.common.expression.Expression; +import com.evolveum.midpoint.model.common.expression.ExpressionEvaluationContext; +import com.evolveum.midpoint.model.common.expression.ExpressionFactory; +import com.evolveum.midpoint.model.common.expression.ExpressionVariables; +import com.evolveum.midpoint.model.impl.ModelObjectResolver; +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.PrismContainer; +import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.Visitable; +import com.evolveum.midpoint.prism.Visitor; +import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.path.ItemPath.CompareResult; +import com.evolveum.midpoint.schema.ObjectDeltaOperation; +import com.evolveum.midpoint.schema.constants.ExpressionConstants; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.MiscSchemaUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.CommunicationException; +import com.evolveum.midpoint.util.exception.ConfigurationException; +import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; +import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; +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.exception.SystemException; +import com.evolveum.midpoint.util.exception.TunnelException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ItemMergeConfigurationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ItemRefMergeConfigurationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.MergeConfigurationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.MergeStategyType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; + +/** + * Class responsible for object merging. This acts as a controller + * for the merge operation and merge preview. + * + * @author semancik + */ +@Component +public class ObjectMerger { + + private static final Trace LOGGER = TraceManager.getTrace(ObjectMerger.class); + + public static final String SIDE_LEFT = "left"; + public static final String SIDE_RIGHT = "right"; + + @Autowired(required = true) + private ModelObjectResolver objectResolver; + + @Autowired(required = true) + private SystemObjectCache systemObjectCache; + + @Autowired(required = true) + private ExpressionFactory expressionFactory; + + @Autowired(required = true) + PrismContext prismContext; + + // TODO: circular dependency to model controller. Not good. + // But cannot fix it right now. TODO: later refactor. + // MID-3459 + @Autowired(required = true) + private ModelController modelController; + + public Collection> mergeObjects(Class type, + String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, ConfigurationException, + ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, + PolicyViolationException, SecurityViolationException { + ObjectDelta objectDelta = computeMergeDelta(type, leftOid, rightOid, mergeConfigurationName, task, result); + + if (objectDelta != null && !objectDelta.isEmpty()) { + Collection> executedDeltas = + modelController.executeChanges(MiscSchemaUtil.createCollection(objectDelta), null, task, result); + + result.computeStatus(); + if (result.isSuccess()) { + // Do not delete the other object if the execution was not success. + // We might need to re-try the merge if it has failed and for that we need the right object. + ObjectDelta deleteDelta = ObjectDelta.createDeleteDelta(type, rightOid, prismContext); + Collection> executedDeleteDeltas = modelController.executeChanges(MiscSchemaUtil.createCollection(deleteDelta), null, task, result); + executedDeltas.addAll(executedDeleteDeltas); + } + + return executedDeltas; + + } else { + return null; + } + } + + public ObjectDelta computeMergeDelta(Class type, String leftOid, String rightOid, + final String mergeConfigurationName, final Task task, final OperationResult result) + throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException { + + final PrismObject objectLeft = objectResolver.getObjectSimple(type, leftOid, null, task, result).asPrismObject(); + final PrismObject objectRight = objectResolver.getObjectSimple(type, rightOid, null, task, result).asPrismObject(); + + PrismObject systemConfiguration = systemObjectCache.getSystemConfiguration(result); + MergeConfigurationType mergeConfiguration = selectConfiguration(systemConfiguration, mergeConfigurationName); + if (mergeConfiguration == null) { + throw new ConfigurationException("No merge configuration defined"); + } + + // The "left" object is always the one that will be the result. We will use its OID. + final ObjectDelta leftObjectDelta = objectLeft.createModifyDelta(); + + final List processedPaths = new ArrayList<>(); + for (ItemRefMergeConfigurationType itemMergeConfig: mergeConfiguration.getItem()) { + ItemPath itemPath = itemMergeConfig.getRef().getItemPath(); + processedPaths.add(itemPath); + ItemDelta itemDelta = mergeItem(objectLeft, objectRight, mergeConfigurationName, itemMergeConfig, itemPath, task, result); + LOGGER.trace("Item {} delta: {}", itemPath, itemDelta); + if (itemDelta != null && !itemDelta.isEmpty()) { + leftObjectDelta.addModification(itemDelta); + } + } + + final ItemMergeConfigurationType defaultItemMergeConfig = mergeConfiguration.getDefault(); + if (defaultItemMergeConfig != null) { + try { + + Visitor visitor = new Visitor() { + @Override + public void visit(Visitable visitable) { + if (!(visitable instanceof Item)) { + return; + } + Item item = (Item)visitable; + + ItemPath itemPath = item.getPath(); + if (itemPath == null || itemPath.isEmpty()) { + return; + } + + boolean found = false; + for (ItemPath processedPath: processedPaths) { + // Need to check for super-paths here. + // E.g. if we have already processed metadata, we do not want to process + // metadata/modifyTimestamp + CompareResult compareResult = processedPath.compareComplex(itemPath); + if (compareResult == CompareResult.EQUIVALENT || compareResult == CompareResult.SUBPATH) { + found = true; + break; + } + } + if (found) { + return; + } + processedPaths.add(itemPath); + + if (item instanceof PrismContainer) { + if (item.getDefinition().isSingleValue()) { + // Ignore single-valued containers such as extension or activation + // we will handle every individual property there. + return; + } else { + // TODO: we may need special handling for multi-value containers + // such as assignment + } + } + + + ItemDelta itemDelta; + try { + itemDelta = mergeItem(objectLeft, objectRight, mergeConfigurationName, defaultItemMergeConfig, itemPath, + task, result); + } catch (SchemaException | ConfigurationException | ExpressionEvaluationException | ObjectNotFoundException e) { + throw new TunnelException(e); + } + LOGGER.trace("Item {} delta (default): {}", itemPath, itemDelta); + if (itemDelta != null && !itemDelta.isEmpty()) { + leftObjectDelta.addModification(itemDelta); + } + } + }; + + objectLeft.accept(visitor); + objectRight.accept(visitor); + + + } catch (TunnelException te) { + if (te.getCause() instanceof SchemaException) { + throw (SchemaException)te.getCause(); + } else if (te.getCause() instanceof ConfigurationException) { + throw (ConfigurationException)te.getCause(); + } else if (te.getCause() instanceof ExpressionEvaluationException) { + throw (ExpressionEvaluationException)te.getCause(); + } else if (te.getCause() instanceof ObjectNotFoundException) { + throw (ObjectNotFoundException)te.getCause(); + } else { + throw new SystemException("Unexpected exception: "+te, te); + } + } + } + + return leftObjectDelta; + + } + + private ItemDelta mergeItem(PrismObject objectLeft, PrismObject objectRight, + String mergeConfigurationName, ItemMergeConfigurationType itemMergeConfig, ItemPath itemPath, + Task task, OperationResult result) throws SchemaException, ConfigurationException, ExpressionEvaluationException, ObjectNotFoundException { + I itemLeft = (I) objectLeft.findItem(itemPath); + I itemRight = (I) objectRight.findItem(itemPath); + if (itemLeft == null && itemRight == null) { + return null; + } + ItemDefinition itemDefinition = null; + if (itemLeft != null) { + itemDefinition = itemLeft.getDefinition(); + } else { + itemDefinition = itemRight.getDefinition(); + } + if (itemDefinition.isOperational()) { + // Skip operational attributes. There are automatically computed, + // we do not want to modify them explicitly. + return null; + } + + Expression valueExpression = null; + if (itemMergeConfig.getValueExpression() != null) { + ExpressionType expressionType = itemMergeConfig.getValueExpression(); + valueExpression = expressionFactory.makeExpression(expressionType, itemDefinition, + "value expression for item " + itemPath + " in merge configuration " + mergeConfigurationName, + task, result); + } + + ItemDelta itemDelta = itemDefinition.createEmptyDelta(itemPath); + MergeStategyType leftStrategy = itemMergeConfig.getLeft(); + MergeStategyType rightStrategy = itemMergeConfig.getRight(); + if (leftStrategy == null || leftStrategy == MergeStategyType.IGNORE) { + if (rightStrategy == null || rightStrategy == MergeStategyType.IGNORE) { + // IGNORE both + if (itemLeft == null) { + return null; + } else { + itemDelta.setValueToReplace(); + return itemDelta; + } + } else { + // IGNORE left, TAKE/EXPRESSION right + if (itemRight == null) { + itemDelta.setValueToReplace(); + } else { + Collection valuesToTake = getValuesToTake(objectLeft, objectRight, + SIDE_RIGHT, itemRight, rightStrategy, valueExpression, task, result); + itemDelta.setValuesToReplace(valuesToTake); + } + return itemDelta; + } + } else { + if (rightStrategy == null || rightStrategy == MergeStategyType.IGNORE) { + if (leftStrategy == MergeStategyType.TAKE) { + // TAKE left, IGNORE right + return null; + } else { + // EXPRESSION left, IGNORE right + Collection valuesToLeave = getValuesToTake(objectLeft, objectRight, + SIDE_LEFT, itemLeft, leftStrategy, valueExpression, task, result); + List currentLeftValues = itemLeft.getValues(); + Collection leftValuesToRemove = diffValues(currentLeftValues, valuesToLeave); + if (leftValuesToRemove != null && !leftValuesToRemove.isEmpty()) { + itemDelta.addValuesToDelete(leftValuesToRemove); + return itemDelta; + } else { + return null; + } + } + } else { + // TAKE/EXPRESSION left, TAKE/EXPRESSION right + if (itemLeft == null) { + Collection valuesToTake = getValuesToTake(objectLeft, objectRight, + SIDE_RIGHT, itemRight, rightStrategy, valueExpression, task, result); + itemDelta.addValuesToAdd(valuesToTake); + return itemDelta; + + } else { + // We want to add only those values that are not yet there. + // E.g. adding assignments that are there can cause unnecessary churn + Collection leftValuesToLeave = getValuesToTake(objectLeft, objectRight, + SIDE_LEFT, itemLeft, leftStrategy, valueExpression, task, result); + Collection rightValuesToTake = getValuesToTake(objectLeft, objectRight, + SIDE_RIGHT, itemRight, rightStrategy, valueExpression, task, result); + + for (PrismValue rightValueToTake: rightValuesToTake) { + if (!PrismValue.collectionContainsEquivalentValue(leftValuesToLeave, rightValueToTake)) { + itemDelta.addValueToAdd(rightValueToTake); + } + } + + List currentLeftValues = itemLeft.getValues(); + Collection leftValuesToRemove = diffValues(currentLeftValues, leftValuesToLeave); + + if (leftValuesToRemove != null && !leftValuesToRemove.isEmpty()) { + itemDelta.addValuesToDelete(leftValuesToRemove); + } + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Merging item {} T/T case:\n leftValuesToLeave: {}\n rightValuesToTake: {}\n leftValuesToRemove: {}\n itemDelta:\n{}", + new Object[]{itemPath, leftValuesToLeave, rightValuesToTake, leftValuesToRemove, itemDelta.debugDump(2)}); + } + + + return itemDelta; + } + } + } + } + + private Collection diffValues(List currentValues, Collection valuesToLeave) { + if (valuesToLeave == null || valuesToLeave.isEmpty()) { + return PrismValue.cloneCollection(currentValues); + } + Collection diff = new ArrayList<>(); + for (PrismValue currentValue: currentValues) { + if (!PrismValue.collectionContainsEquivalentValue(valuesToLeave, currentValue)) { + diff.add(currentValue.clone()); + } + } + return diff; + } + + private Collection getValuesToTake(PrismObject objectLeft, PrismObject objectRight, + String side, I origItem, MergeStategyType strategy, Expression valueExpression, Task task, OperationResult result) + throws ConfigurationException, SchemaException, ExpressionEvaluationException, ObjectNotFoundException { + if (strategy == MergeStategyType.TAKE) { + return cleanContainerIds(origItem.getClonedValues()); + } else if (strategy == MergeStategyType.EXPRESSION) { + if (valueExpression == null) { + throw new ConfigurationException("Expression strategy specified but no expression present"); + } + List origValues = origItem.getValues(); + Collection valuesToTake = new ArrayList<>(origValues.size()); + for (PrismValue origValue: origValues) { + Collection expressionOutput = evaluateValueExpression(objectLeft, objectRight, side, origValue, valueExpression, task, result); + if (expressionOutput != null) { + valuesToTake.addAll(expressionOutput); + } + } + return cleanContainerIds(valuesToTake); + } else { + throw new ConfigurationException("Unknown strategy "+strategy); + } + } + + + private Collection cleanContainerIds(Collection pvals) { + if (pvals == null) { + return null; + } + for (PrismValue pval: pvals) { + if (pval instanceof PrismContainerValue) { + ((PrismContainerValue)pval).setId(null); + } + } + return pvals; + } + + + private Collection evaluateValueExpression(PrismObject objectLeft, PrismObject objectRight, String side, PrismValue origValue, Expression valueExpression, + Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException { + ExpressionVariables variables = new ExpressionVariables(); + variables.addVariableDefinition(ExpressionConstants.VAR_SIDE, side); + variables.addVariableDefinition(ExpressionConstants.VAR_OBJECT_LEFT, side); + variables.addVariableDefinition(ExpressionConstants.VAR_OBJECT_RIGHT, side); + variables.addVariableDefinition(ExpressionConstants.VAR_INPUT, origValue); + variables.addVariableDefinition(ExpressionConstants.VAR_VALUE, origValue); + ExpressionEvaluationContext exprContext = new ExpressionEvaluationContext(null, variables, "for value "+origValue, task, result); + PrismValueDeltaSetTriple triple = valueExpression.evaluate(exprContext); + if (triple == null) { + return null; + } + return triple.getNonNegativeValues(); + } + + private MergeConfigurationType selectConfiguration( + PrismObject systemConfiguration, String mergeConfigurationName) throws ConfigurationException { + if (StringUtils.isBlank(mergeConfigurationName)) { + throw new IllegalArgumentException("Merge configuration name not specified"); + } + for (MergeConfigurationType mergeConfiguration: systemConfiguration.asObjectable().getMergeConfiguration()) { + if (mergeConfigurationName.equals(mergeConfiguration.getName())) { + return mergeConfiguration; + } + } + throw new ConfigurationException("Merge configuration with name '"+mergeConfigurationName+"' was not found"); + } + +} diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java index 6567a79392b..68373bc7157 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/AbstractConfiguredModelIntegrationTest.java @@ -223,6 +223,9 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractModelIntegra protected static final String USER_JACK_FULL_NAME = "Jack Sparrow"; protected static final String USER_JACK_GIVEN_NAME = "Jack"; protected static final String USER_JACK_FAMILY_NAME = "Sparrow"; + protected static final String USER_JACK_ADDITIONAL_NAME = "Jackie"; + protected static final String USER_JACK_EMPLOYEE_TYPE = "CAPTAIN"; + protected static final String USER_JACK_LOCALITY = "Caribbean"; protected static final String USER_JACK_PASSWORD = "deadmentellnotales"; protected static final File USER_BARBOSSA_FILE = new File(COMMON_DIR, "user-barbossa.xml"); @@ -236,6 +239,7 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractModelIntegra protected static final String USER_GUYBRUSH_FULL_NAME = "Guybrush Threepwood"; protected static final String USER_GUYBRUSH_GIVEN_NAME = "Guybrush"; protected static final String USER_GUYBRUSH_FAMILY_NAME = "Threepwood"; + protected static final String USER_GUYBRUSH_LOCALITY = "Melee Island"; // Largo does not have a full name set, employeeType=PIRATE protected static final File USER_LARGO_FILE = new File(COMMON_DIR, "user-largo.xml"); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMerge.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMerge.java new file mode 100644 index 00000000000..ca192dca2c4 --- /dev/null +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMerge.java @@ -0,0 +1,423 @@ +/* + * Copyright (c) 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.model.intest; + +import static com.evolveum.midpoint.test.IntegrationTestTools.display; +import static org.testng.AssertJUnit.assertEquals; + +import java.io.File; + +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.testng.annotations.Test; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.util.PrismAsserts; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.FocusTypeUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.test.util.TestUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; + +/** + * @author semancik + * + */ +@ContextConfiguration(locations = {"classpath:ctx-model-intest-test-main.xml"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class TestMerge extends AbstractInitializedModelIntegrationTest { + + public static final File TEST_DIR = new File("src/test/resources/merge"); + + public static final String MERGE_CONFIG_DEFAULT_NAME = "default"; + public static final String MERGE_CONFIG_EXPRESSION_NAME = "expression"; + + @Override + public void initSystem(Task initTask, OperationResult initResult) throws Exception { + super.initSystem(initTask, initResult); + + modifyUserAdd(USER_GUYBRUSH_OID, UserType.F_EMPLOYEE_TYPE, initTask, initResult, + "SAILOR", "PIRATE WANNABE"); + modifyUserAdd(USER_GUYBRUSH_OID, UserType.F_ORGANIZATION, initTask, initResult, + createPolyString("Pirate Wannabes"), createPolyString("Sailors"), createPolyString("Rum Club"), createPolyString("Lovers")); + assignRole(USER_GUYBRUSH_OID, ROLE_SAILOR_OID, initTask, initResult); + assignRole(USER_GUYBRUSH_OID, ROLE_EMPTY_OID, initTask, initResult); + assignRole(USER_GUYBRUSH_OID, ROLE_THIEF_OID, initTask, initResult); + + modifyUserAdd(USER_JACK_OID, UserType.F_ORGANIZATION, initTask, initResult, + createPolyString("Pirate Brethren"), createPolyString("Sailors"), createPolyString("Rum Club"), createPolyString("Drinkers")); + assignRole(USER_JACK_OID, ROLE_SAILOR_OID, initTask, initResult); + assignRole(USER_JACK_OID, ROLE_EMPTY_OID, initTask, initResult); + assignRole(USER_JACK_OID, ROLE_PIRATE_OID, initTask, initResult); + assignRole(USER_JACK_OID, ROLE_NICE_PIRATE_OID, initTask, initResult); + } + + /** + * MID-3460 + */ + @Test + public void test100MergeJackGuybrushPreviewDelta() throws Exception { + final String TEST_NAME = "test100MergeJackGuybrushPreviewDelta"; + TestUtil.displayTestTile(this, TEST_NAME); + + Task task = taskManager.createTaskInstance(TestMerge.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + PrismObject userJackBefore = getUser(USER_JACK_OID); + display("Jack before", userJackBefore); + + PrismObject userGuybrushBefore = getUser(USER_GUYBRUSH_OID); + display("Guybrush before", userGuybrushBefore); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + ObjectDelta delta = + modelInteractionService.mergeObjectsPreviewDelta(UserType.class, + USER_JACK_OID, USER_GUYBRUSH_OID, MERGE_CONFIG_DEFAULT_NAME, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + display("Delta", delta); + + PrismAsserts.assertIsModify(delta); + assertEquals("Wrong delta OID", USER_JACK_OID, delta.getOid()); + PrismAsserts.assertNoItemDelta(delta, UserType.F_NAME); + PrismAsserts.assertNoItemDelta(delta, UserType.F_GIVEN_NAME); + PrismAsserts.assertPropertyReplace(delta, UserType.F_FAMILY_NAME); + PrismAsserts.assertPropertyReplace(delta, UserType.F_FULL_NAME, + createPolyString(USER_GUYBRUSH_FULL_NAME)); + PrismAsserts.assertPropertyReplace(delta, UserType.F_ADDITIONAL_NAME); + PrismAsserts.assertPropertyReplace(delta, UserType.F_LOCALITY, + createPolyString(USER_GUYBRUSH_LOCALITY)); + PrismAsserts.assertPropertyAdd(delta, UserType.F_EMPLOYEE_TYPE, + "SAILOR", "PIRATE WANNABE"); + PrismAsserts.assertPropertyAdd(delta, UserType.F_ORGANIZATION, + createPolyString("Pirate Wannabes"), createPolyString("Lovers")); + PrismAsserts.assertNoItemDelta(delta, UserType.F_ACTIVATION); + PrismAsserts.assertNoItemDelta(delta, + new ItemPath(UserType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS)); + PrismAsserts.assertNoItemDelta(delta, UserType.F_ROLE_MEMBERSHIP_REF); + + PrismAsserts.assertContainerAdd(delta, UserType.F_ASSIGNMENT, + FocusTypeUtil.createRoleAssignment(ROLE_THIEF_OID)); + + } + + /** + * MID-3460 + */ + @Test + public void test102MergeJackGuybrushPreviewObject() throws Exception { + final String TEST_NAME = "test102MergeJackGuybrushPreviewObject"; + TestUtil.displayTestTile(this, TEST_NAME); + + Task task = taskManager.createTaskInstance(TestMerge.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + PrismObject object = + modelInteractionService.mergeObjectsPreviewObject(UserType.class, + USER_JACK_OID, USER_GUYBRUSH_OID, MERGE_CONFIG_DEFAULT_NAME, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + display("Object", object); + + assertEquals("Wrong object OID", USER_JACK_OID, object.getOid()); + PrismAsserts.assertPropertyValue(object, + UserType.F_NAME, createPolyString(USER_JACK_USERNAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_GIVEN_NAME, createPolyString(USER_JACK_GIVEN_NAME)); + PrismAsserts.assertNoItem(object, UserType.F_FAMILY_NAME); + PrismAsserts.assertPropertyValue(object, + UserType.F_FULL_NAME, createPolyString(USER_GUYBRUSH_FULL_NAME)); + PrismAsserts.assertNoItem(object, UserType.F_ADDITIONAL_NAME); + PrismAsserts.assertPropertyValue(object, + UserType.F_LOCALITY, createPolyString(USER_GUYBRUSH_LOCALITY)); + PrismAsserts.assertPropertyValue(object, + UserType.F_EMPLOYEE_TYPE, USER_JACK_EMPLOYEE_TYPE, "SAILOR", "PIRATE WANNABE"); + PrismAsserts.assertPropertyValue(object, + UserType.F_ORGANIZATION, + createPolyString("Pirate Brethren"), createPolyString("Sailors"), createPolyString("Rum Club"), + createPolyString("Pirate Wannabes"), createPolyString("Lovers"), createPolyString("Drinkers")); + + assertAssignedRoles(object, ROLE_SAILOR_OID, ROLE_EMPTY_OID, ROLE_THIEF_OID, + ROLE_PIRATE_OID, ROLE_NICE_PIRATE_OID); + } + + /** + * MID-3460 + */ + @Test + public void test110MergeGuybrushJackPreviewDelta() throws Exception { + final String TEST_NAME = "test110MergeGuybrushJackPreviewDelta"; + TestUtil.displayTestTile(this, TEST_NAME); + + Task task = taskManager.createTaskInstance(TestMerge.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + PrismObject userGuybrushBefore = getUser(USER_GUYBRUSH_OID); + display("Guybrush before", userGuybrushBefore); + + PrismObject userJackBefore = getUser(USER_JACK_OID); + display("Jack before", userJackBefore); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + ObjectDelta delta = + modelInteractionService.mergeObjectsPreviewDelta(UserType.class, + USER_GUYBRUSH_OID, USER_JACK_OID, MERGE_CONFIG_DEFAULT_NAME, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + display("Delta", delta); + + PrismAsserts.assertIsModify(delta); + assertEquals("Wrong delta OID", USER_GUYBRUSH_OID, delta.getOid()); + PrismAsserts.assertNoItemDelta(delta, UserType.F_NAME); + PrismAsserts.assertNoItemDelta(delta, UserType.F_GIVEN_NAME); + PrismAsserts.assertPropertyReplace(delta, UserType.F_FAMILY_NAME); + PrismAsserts.assertPropertyReplace(delta, UserType.F_FULL_NAME, + createPolyString(USER_JACK_FULL_NAME)); + PrismAsserts.assertPropertyReplace(delta, UserType.F_ADDITIONAL_NAME, + createPolyString(USER_JACK_ADDITIONAL_NAME)); + PrismAsserts.assertPropertyReplace(delta, UserType.F_LOCALITY, + createPolyString(USER_JACK_LOCALITY)); + PrismAsserts.assertPropertyAdd(delta, UserType.F_EMPLOYEE_TYPE, + USER_JACK_EMPLOYEE_TYPE); + PrismAsserts.assertPropertyAdd(delta, UserType.F_ORGANIZATION, + createPolyString("Pirate Brethren"), createPolyString("Drinkers")); + PrismAsserts.assertNoItemDelta(delta, UserType.F_ACTIVATION); + PrismAsserts.assertNoItemDelta(delta, + new ItemPath(UserType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS)); + PrismAsserts.assertNoItemDelta(delta, UserType.F_ROLE_MEMBERSHIP_REF); + + PrismAsserts.assertContainerAdd(delta, UserType.F_ASSIGNMENT, + FocusTypeUtil.createRoleAssignment(ROLE_PIRATE_OID), + FocusTypeUtil.createRoleAssignment(ROLE_NICE_PIRATE_OID)); + + + } + + /** + * MID-3460 + */ + @Test + public void test112MergeGuybrushJackPreviewObject() throws Exception { + final String TEST_NAME = "test112MergeGuybrushJackPreviewObject"; + TestUtil.displayTestTile(this, TEST_NAME); + + Task task = taskManager.createTaskInstance(TestMerge.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + PrismObject object = + modelInteractionService.mergeObjectsPreviewObject(UserType.class, + USER_GUYBRUSH_OID, USER_JACK_OID, MERGE_CONFIG_DEFAULT_NAME, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + display("Object", object); + + assertEquals("Wrong object OID", USER_GUYBRUSH_OID, object.getOid()); + PrismAsserts.assertPropertyValue(object, + UserType.F_NAME, createPolyString(USER_GUYBRUSH_USERNAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_GIVEN_NAME, createPolyString(USER_GUYBRUSH_GIVEN_NAME)); + PrismAsserts.assertNoItem(object, UserType.F_FAMILY_NAME); + PrismAsserts.assertPropertyValue(object, + UserType.F_FULL_NAME, createPolyString(USER_JACK_FULL_NAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_ADDITIONAL_NAME, createPolyString(USER_JACK_ADDITIONAL_NAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_LOCALITY, createPolyString(USER_JACK_LOCALITY)); + PrismAsserts.assertPropertyValue(object, + UserType.F_EMPLOYEE_TYPE, USER_JACK_EMPLOYEE_TYPE, "SAILOR", "PIRATE WANNABE"); + PrismAsserts.assertPropertyValue(object, + UserType.F_ORGANIZATION, + createPolyString("Pirate Brethren"), createPolyString("Sailors"), createPolyString("Rum Club"), + createPolyString("Pirate Wannabes"), createPolyString("Lovers"), createPolyString("Drinkers")); + + assertAssignedRoles(object, ROLE_SAILOR_OID, ROLE_EMPTY_OID, ROLE_THIEF_OID, + ROLE_PIRATE_OID, ROLE_NICE_PIRATE_OID); + + } + + /** + * MID-3460 + */ + @Test + public void test200MergeJackGuybrushExpressionPreviewDelta() throws Exception { + final String TEST_NAME = "test200MergeJackGuybrushExpressionPreviewDelta"; + TestUtil.displayTestTile(this, TEST_NAME); + + Task task = taskManager.createTaskInstance(TestMerge.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + PrismObject userJackBefore = getUser(USER_JACK_OID); + display("Jack before", userJackBefore); + + PrismObject userGuybrushBefore = getUser(USER_GUYBRUSH_OID); + display("Guybrush before", userGuybrushBefore); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + ObjectDelta delta = + modelInteractionService.mergeObjectsPreviewDelta(UserType.class, + USER_JACK_OID, USER_GUYBRUSH_OID, MERGE_CONFIG_EXPRESSION_NAME, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + display("Delta", delta); + + PrismAsserts.assertIsModify(delta); + assertEquals("Wrong delta OID", USER_JACK_OID, delta.getOid()); + PrismAsserts.assertNoItemDelta(delta, UserType.F_NAME); + PrismAsserts.assertNoItemDelta(delta, UserType.F_GIVEN_NAME); + PrismAsserts.assertNoItemDelta(delta, UserType.F_FAMILY_NAME); + PrismAsserts.assertNoItemDelta(delta, UserType.F_FULL_NAME); + PrismAsserts.assertNoItemDelta(delta, UserType.F_ADDITIONAL_NAME); + PrismAsserts.assertPropertyAdd(delta, UserType.F_EMPLOYEE_TYPE, + "SAILOR"); + PrismAsserts.assertPropertyAdd(delta, UserType.F_ORGANIZATION, + createPolyString("Pirate Wannabes")); + PrismAsserts.assertPropertyDelete(delta, UserType.F_ORGANIZATION, + createPolyString("Sailors"), createPolyString("Drinkers")); + PrismAsserts.assertNoItemDelta(delta, UserType.F_ACTIVATION); + PrismAsserts.assertNoItemDelta(delta, + new ItemPath(UserType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS)); + PrismAsserts.assertNoItemDelta(delta, UserType.F_ROLE_MEMBERSHIP_REF); + + PrismAsserts.assertContainerAdd(delta, UserType.F_ASSIGNMENT, + FocusTypeUtil.createRoleAssignment(ROLE_THIEF_OID)); + } + + /** + * MID-3460 + */ + @Test + public void test202MergeJackGuybrushExpressionPreviewObject() throws Exception { + final String TEST_NAME = "test202MergeJackGuybrushExpressionPreviewObject"; + TestUtil.displayTestTile(this, TEST_NAME); + + Task task = taskManager.createTaskInstance(TestMerge.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + PrismObject object = + modelInteractionService.mergeObjectsPreviewObject(UserType.class, + USER_JACK_OID, USER_GUYBRUSH_OID, MERGE_CONFIG_EXPRESSION_NAME, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + display("Object", object); + + assertEquals("Wrong object OID", USER_JACK_OID, object.getOid()); + PrismAsserts.assertPropertyValue(object, + UserType.F_NAME, createPolyString(USER_JACK_USERNAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_GIVEN_NAME, createPolyString(USER_JACK_GIVEN_NAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_FAMILY_NAME, createPolyString(USER_JACK_FAMILY_NAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_FULL_NAME, createPolyString(USER_JACK_FULL_NAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_ADDITIONAL_NAME, createPolyString(USER_JACK_ADDITIONAL_NAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_LOCALITY, createPolyString(USER_JACK_LOCALITY)); + PrismAsserts.assertPropertyValue(object, + UserType.F_EMPLOYEE_TYPE, USER_JACK_EMPLOYEE_TYPE, "SAILOR"); + PrismAsserts.assertPropertyValue(object, + UserType.F_ORGANIZATION, + createPolyString("Pirate Brethren"), createPolyString("Rum Club"), + createPolyString("Pirate Wannabes")); + + assertAssignedRoles(object, ROLE_SAILOR_OID, ROLE_EMPTY_OID, ROLE_THIEF_OID, + ROLE_PIRATE_OID, ROLE_NICE_PIRATE_OID); + } + + + + /** + * MID-3460 + */ + @Test + public void test500MergeJackGuybrush() throws Exception { + final String TEST_NAME = "test500MergeJackGuybrush"; + TestUtil.displayTestTile(this, TEST_NAME); + + Task task = taskManager.createTaskInstance(TestMerge.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modelService.mergeObjects(UserType.class, + USER_JACK_OID, USER_GUYBRUSH_OID, MERGE_CONFIG_DEFAULT_NAME, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + PrismObject object = getObject(UserType.class, USER_JACK_OID); + display("Object", object); + + assertEquals("Wrong object OID", USER_JACK_OID, object.getOid()); + PrismAsserts.assertPropertyValue(object, + UserType.F_NAME, createPolyString(USER_JACK_USERNAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_GIVEN_NAME, createPolyString(USER_JACK_GIVEN_NAME)); + PrismAsserts.assertNoItem(object, UserType.F_FAMILY_NAME); + PrismAsserts.assertPropertyValue(object, + UserType.F_FULL_NAME, createPolyString(USER_GUYBRUSH_FULL_NAME)); + PrismAsserts.assertNoItem(object, UserType.F_ADDITIONAL_NAME); + PrismAsserts.assertPropertyValue(object, + UserType.F_LOCALITY, createPolyString(USER_GUYBRUSH_LOCALITY)); + PrismAsserts.assertPropertyValue(object, + UserType.F_EMPLOYEE_TYPE, USER_JACK_EMPLOYEE_TYPE, "SAILOR", "PIRATE WANNABE"); + + assertAssignedRoles(object, ROLE_SAILOR_OID, ROLE_EMPTY_OID, ROLE_THIEF_OID, + ROLE_PIRATE_OID, ROLE_NICE_PIRATE_OID); + + assertNoObject(UserType.class, USER_GUYBRUSH_OID); + + } +} diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java index 00855d015a8..4839e2fab2d 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/orgstruct/TestOrgStruct.java @@ -342,7 +342,7 @@ public void test211JackAssignMinistryOfOffenseMinister() throws Exception { // THEN PrismObject userJack = getUser(USER_JACK_OID); display("User jack after", userJack); - assertAssignedOrgs(userJack, ORG_MINISTRY_OF_OFFENSE_OID); + assertAssignedOrgs(userJack, ORG_MINISTRY_OF_OFFENSE_OID, ORG_MINISTRY_OF_OFFENSE_OID); assertHasOrgs(userJack, ORG_MINISTRY_OF_OFFENSE_OID, ORG_MINISTRY_OF_OFFENSE_OID, ORG_MINISTRY_OF_DEFENSE_OID); assertAssignedOrg(userJack, ORG_MINISTRY_OF_OFFENSE_OID, SchemaConstants.ORG_MANAGER); assertHasOrg(userJack, ORG_MINISTRY_OF_OFFENSE_OID, SchemaConstants.ORG_MANAGER); @@ -770,7 +770,7 @@ public void test350AddJackAsMinistryOfOffenseManager() throws Exception { // THEN userJack = getUser(USER_JACK_OID); display("User jack after", userJack); - assertAssignedOrgs(userJack, ORG_MINISTRY_OF_OFFENSE_OID); + assertAssignedOrgs(userJack, ORG_MINISTRY_OF_OFFENSE_OID, ORG_MINISTRY_OF_OFFENSE_OID); assertHasOrgs(userJack, ORG_MINISTRY_OF_OFFENSE_OID, ORG_MINISTRY_OF_OFFENSE_OID); assertAssignedOrg(userJack, ORG_MINISTRY_OF_OFFENSE_OID, SchemaConstants.ORG_MANAGER); assertHasOrg(userJack, ORG_MINISTRY_OF_OFFENSE_OID, SchemaConstants.ORG_MANAGER); diff --git a/model/model-intest/src/test/resources/common/system-configuration.xml b/model/model-intest/src/test/resources/common/system-configuration.xml index f1fd9694190..4d93bcc4508 100644 --- a/model/model-intest/src/test/resources/common/system-configuration.xml +++ b/model/model-intest/src/test/resources/common/system-configuration.xml @@ -184,4 +184,145 @@ Jamaica + + + default + + name + take + + + givenName + take + ignore + + + familyName + + + fullName + take + + + employeeType + take + take + + + organization + take + take + + + organizationalUnit + take + + + activation + take + + + assignment + take + take + + + linkRef + take + + + take + + + + + empty + + + + allRight + + take + + + + + allLeft + + take + + + + + expression + + name + take + + + givenName + take + + + familyName + take + + + fullName + take + + + employeeType + take + expression + + + + + + organization + expression + expression + + + + + + organizationalUnit + take + + + activation + take + + + assignment + take + take + + + linkRef + take + + + take + + + diff --git a/model/model-intest/src/test/resources/logback-test.xml b/model/model-intest/src/test/resources/logback-test.xml index c1e26eb4089..71150abe2ee 100644 --- a/model/model-intest/src/test/resources/logback-test.xml +++ b/model/model-intest/src/test/resources/logback-test.xml @@ -80,7 +80,7 @@ - + @@ -99,6 +99,7 @@ + diff --git a/model/model-intest/testng-integration.xml b/model/model-intest/testng-integration.xml index a9afa71b033..b76a092d39a 100644 --- a/model/model-intest/testng-integration.xml +++ b/model/model-intest/testng-integration.xml @@ -56,6 +56,7 @@ + diff --git a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java index d25e03cbcaf..7d3a89ee2aa 100644 --- a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java +++ b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java @@ -1367,6 +1367,14 @@ protected void assertAssignedRole(PrismObject user, Str MidPointAsserts.assertAssignedRole(user, roleOid); } + protected static void assertAssignedRoles(PrismObject user, String... roleOids) { + MidPointAsserts.assertAssignedRoles(user, roleOids); + } + + protected static void assertAssignedOrgs(PrismObject user, String... orgOids) { + MidPointAsserts.assertAssignedOrgs(user, orgOids); + } + protected void assertRoleMembershipRef(PrismObject focus, String... roleOids) { List refOids = new ArrayList(); for (ObjectReferenceType ref: focus.asObjectable().getRoleMembershipRef()) { @@ -1417,12 +1425,6 @@ protected void assertAssignedOrg(PrismObject focus, String protected void assertAssignedOrg(PrismObject focus, String orgOid) { MidPointAsserts.assertAssignedOrg(focus, orgOid); } - - protected void assertAssignedOrgs(PrismObject user, String... orgOids) throws Exception { - for (String orgOid: orgOids) { - assertAssignedOrg(user, orgOid); - } - } protected void assertAssignedOrg(PrismObject user, PrismObject org) { MidPointAsserts.assertAssignedOrg(user, org.getOid()); diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java index a966f68f845..2012e8f79dd 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java @@ -42,6 +42,7 @@ import com.evolveum.midpoint.prism.delta.PropertyDelta; import com.evolveum.midpoint.prism.match.MatchingRule; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.AndFilter; import com.evolveum.midpoint.prism.query.EqualFilter; import com.evolveum.midpoint.prism.query.ObjectFilter; @@ -85,6 +86,7 @@ import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; import org.apache.commons.lang.StringUtils; @@ -1133,4 +1135,12 @@ protected void assertUserLockout(PrismObject user, LockoutStatusType e assertEquals("Wrong lockout status of "+user, expectedStatus, activationType.getLockoutStatus()); } } + + protected PolyString createPolyString(String string) { + return PrismTestUtil.createPolyString(string); + } + + protected PolyStringType createPolyStringType(String string) { + return PrismTestUtil.createPolyStringType(string); + } }