From 61efd9f46a1c514073c4af649b9a8b4696a918c3 Mon Sep 17 00:00:00 2001 From: ozkanbayraktar Date: Tue, 11 Oct 2016 10:34:33 +0200 Subject: [PATCH 01/15] refresh facility is added to the the table on the audit log viewer page by using the search button --- .../midpoint/web/page/admin/reports/PageAuditLogViewer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java index 9b41ed418da..84891f1b9f4 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java @@ -113,7 +113,7 @@ private void initParametersPanel(Form mainForm){ AjaxButton ajaxButton = new AjaxButton(ID_SEARCH_BUTTON, createStringResource("BasicSearchPanel.search")) { @Override public void onClick(AjaxRequestTarget arg0) { - Form mainForm = (Form)get(ID_MAIN_FORM); + Form mainForm = (Form)getParent().getParent(); initTable(mainForm); arg0.add(mainForm); // TODO Auto-generated method stub @@ -131,7 +131,8 @@ private void initTable(Form mainForm){ (int) getItemsPerPage(UserProfileStorage.TableId.PAGE_AUDIT_LOG_VIEWER)); table.setShowPaging(true); table.setOutputMarkupId(true); - mainForm.add(table); + // mainForm.add(table); + mainForm.addOrReplace(table); } private List, String>> initColumns() { From cb7d1409d3fcc68585273bdbf69a4a049546d0e1 Mon Sep 17 00:00:00 2001 From: honchar Date: Tue, 11 Oct 2016 11:06:04 +0200 Subject: [PATCH 02/15] role catalog default view --- .../web/page/self/PageAssignmentShoppingKart.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) 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 1226b630247..607b516689b 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 @@ -53,6 +53,7 @@ public class PageAssignmentShoppingKart extends PageSelf { private IModel viewModel; private AssignmentViewType currentViewType = AssignmentViewType.ROLE_CATALOG_VIEW; private String catalogOid = null; + private boolean isFirstInit = true; public PageAssignmentShoppingKart() { initLayout(); @@ -161,9 +162,17 @@ private QName getViewTypeClass() { private Component initMainPanel(){ if (StringUtils.isEmpty(catalogOid)) { - Label panel = new Label(ID_MAIN_PANEL, createStringResource("PageAssignmentShoppingKart.roleCatalogIsNotConfigured")); - panel.setOutputMarkupId(true); - return panel; + if (isFirstInit){ + isFirstInit = false; + currentViewType = AssignmentViewType.ROLE_TYPE; + AssignmentCatalogPanel panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, getViewTypeClass(), PageAssignmentShoppingKart.this); + panel.setOutputMarkupId(true); + return panel; + } else { + 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); panel.setOutputMarkupId(true); From f4c970a06ac94fc983b9c770c2e4c1bef99285a1 Mon Sep 17 00:00:00 2001 From: ozkanbayraktar Date: Tue, 11 Oct 2016 11:09:23 +0200 Subject: [PATCH 03/15] AuditSearchDto is integrated --- .../page/admin/reports/PageAuditLogViewer.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java index 84891f1b9f4..4e0ac89017b 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java @@ -14,6 +14,7 @@ import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.util.ListModel; import com.evolveum.midpoint.audit.api.AuditEventRecord; @@ -30,6 +31,7 @@ import com.evolveum.midpoint.web.component.util.SelectableBean; import com.evolveum.midpoint.web.page.admin.configuration.PageAdminConfiguration; import com.evolveum.midpoint.web.page.admin.reports.dto.AuditEventRecordProvider; +import com.evolveum.midpoint.web.page.admin.reports.dto.AuditSearchDto; import com.evolveum.midpoint.web.session.UserProfileStorage; import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventRecordType; @@ -59,20 +61,26 @@ public class PageAuditLogViewer extends PageBase{ private static final String ID_MAIN_FORM = "mainForm"; private static final String ID_SEARCH_BUTTON = "searchButton"; + /* private IModel fromModel; private IModel toModel; private IModel initiatorModel; private IModel channelModel; private IModel channelListModel; private IModel propertyModel; - + */ + + private IModel auditSearchDto; + public PageAuditLogViewer(){ + /* fromModel = new Model(); toModel = new Model(); initiatorModel = new Model(); channelModel = new Model(); channelListModel = new ListModel(new WebComponentUtil().getChannelList()); propertyModel = new Model(); + */ initLayout(); } @@ -90,6 +98,14 @@ private void initParametersPanel(Form mainForm){ parametersPanel.setOutputMarkupId(true); mainForm.add(parametersPanel); + IModel fromModel = new PropertyModel<>(auditSearchDto, "fromGreg"); + IModel toModel = new PropertyModel<>(auditSearchDto, "toGreg"); + IModel initiatorModel = new PropertyModel<>(auditSearchDto, "initiator"); + IModel channelModel = new PropertyModel<>(auditSearchDto, "channel"); + IModel propertyModel = new PropertyModel<>(auditSearchDto, "property"); + + IModel channelListModel = new ListModel(new WebComponentUtil().getChannelList()); + final DatePanel from = new DatePanel(ID_FROM, fromModel); from.setOutputMarkupId(true); parametersPanel.add(from); From 513e47e6d47ef920b671c77c3782a97788d70722 Mon Sep 17 00:00:00 2001 From: honchar Date: Tue, 11 Oct 2016 15:27:46 +0200 Subject: [PATCH 04/15] role catalog restructuring panels --- .../assignment/AssignmentCatalogPanel.java | 74 +++++++++--- .../assignment/CatalogItemsPanel.html | 11 +- .../assignment/CatalogItemsPanel.java | 109 ++++++++++++++---- .../page/self/PageAssignmentShoppingKart.html | 3 - .../page/self/PageAssignmentShoppingKart.java | 77 +------------ 5 files changed, 159 insertions(+), 115 deletions(-) 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..b6ed335a625 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 @@ -47,6 +47,10 @@ public class AssignmentCatalogPanel extends BasePane private static String ID_CATALOG_ITEMS_PANEL = "catalogItemsPanel"; private PageBase pageBase; + private IModel rootOidModel; + private String rootOid; + private IModel viewTypeClassModel; + private QName viewTypeClass; public AssignmentCatalogPanel(String id) { super(id); @@ -55,21 +59,29 @@ public AssignmentCatalogPanel(String id) { public AssignmentCatalogPanel(String id, String rootOid, PageBase pageBase) { super(id); this.pageBase = pageBase; - initLayout(null, rootOid); + this.rootOid = rootOid; + this.viewTypeClass = null; + initLayout(); } public AssignmentCatalogPanel(String id, QName viewTypeClass, PageBase pageBase) { super(id); this.pageBase = pageBase; - initLayout(viewTypeClass, null); + this.viewTypeClass = viewTypeClass; + this.rootOid = null; + 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 (viewTypeClass == null) { OrgTreePanel treePanel = new OrgTreePanel(ID_TREE_PANEL, new IModel() { @Override public String getObject() { @@ -106,38 +118,72 @@ 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, viewTypeClassModel, pageBase); + if (viewTypeClass == null) { 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()); + viewTypeClassModel.setObject(null); + CatalogItemsPanel catalogItemsPanel = new CatalogItemsPanel(ID_CATALOG_ITEMS_PANEL, rootOidModel, viewTypeClassModel, 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() { + + } + }; + viewTypeClassModel = new IModel() { + @Override + public QName getObject() { + return viewTypeClass; + } + + @Override + public void setObject(QName qName) { + viewTypeClass = qName; + } + + @Override + public void detach() { + + } + }; + } } 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..2c9666562f3 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,13 +17,16 @@ 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 baed519bd1a..6cb9c87851c 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 @@ -61,16 +61,13 @@ public class PageAssignmentShoppingKart extends PageSelf { 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; + private QName currentViewClass; public PageAssignmentShoppingKart() { initLayout(); @@ -81,24 +78,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()); } @@ -127,62 +106,12 @@ 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); - panel.setOutputMarkupId(true); - } else { - panel = initMainPanel(); - } - ((Form) PageAssignmentShoppingKart.this.get(ID_MAIN_FORM)).addOrReplace(panel); - target.add(get(ID_MAIN_FORM)); - } - }); - 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)) { if (isFirstInit){ isFirstInit = false; - currentViewType = AssignmentViewType.ROLE_TYPE; - AssignmentCatalogPanel panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, getViewTypeClass(), PageAssignmentShoppingKart.this); + currentViewClass = RoleType.COMPLEX_TYPE; + AssignmentCatalogPanel panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, currentViewClass, PageAssignmentShoppingKart.this); panel.setOutputMarkupId(true); return panel; } else { From 6bf71953464b00be002436bfae27a744be8dbd83 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Tue, 11 Oct 2016 16:28:06 +0200 Subject: [PATCH 05/15] Basic implementation of object merge (model) (MID-3460) --- .../midpoint/prism/util/PrismAsserts.java | 10 +- .../xml/ns/public/common/common-core-3.xsd | 92 ++++++ .../model/api/ModelInteractionService.java | 10 + .../midpoint/model/api/ModelService.java | 20 +- .../impl/controller/ModelController.java | 37 +++ .../ModelInteractionServiceImpl.java | 50 ++++ .../model/impl/controller/ObjectMerger.java | 272 ++++++++++++++++++ ...bstractConfiguredModelIntegrationTest.java | 4 + .../midpoint/model/intest/TestMerge.java | 242 ++++++++++++++++ .../resources/common/system-configuration.xml | 27 ++ .../src/test/resources/logback-test.xml | 3 +- model/model-intest/testng-integration.xml | 1 + 12 files changed, 762 insertions(+), 6 deletions(-) create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ObjectMerger.java create mode 100644 model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMerge.java 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..421a62ecdf8 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,11 +417,15 @@ 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) { 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..0bc7ca1ade5 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,20 @@ + + + + + Configuration for object merging. E.g. for merging two users. + Note: this is a single-valued item now. But it will most likely be + switched to multi-valued item in future midPoint versions. + + + 3.5 + + + + @@ -12470,5 +12484,83 @@ + + + + + TODO + + + + + + + + + + + + + + + + + TODO + + + + + + + + + + + + + + + TODO + + + + + + + + + + + + + + + + + + TODO + + + + + + + + + + + + + + + + + + + + + + + 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..5e0997e3fe9 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, Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, ConfigurationException; + + PrismObject mergeObjectsPreviewObject(Class type, + String leftOid, String rightOid, Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, ConfigurationException; } 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..8f0a3b79ba4 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,24 @@ 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 task + * @param result + * @return + */ + Collection> mergeObjects(Class type, String leftOid, String rightOid, 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..faa6ca60a33 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,38 @@ public AccessCertificationCampaignType createCampaign(String definitionOid, Task return getCertificationManagerChecked().createCampaign(definitionOid, task, parentResult); } //endregion + + @Override + public Collection> mergeObjects(Class type, String leftOid, String rightOid, 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, 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..4734e17af24 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, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, ConfigurationException { + OperationResult result = parentResult.createMinorSubresult(MERGE_OBJECTS_PREVIEW_DELTA); + + try { + + ObjectDelta objectDelta = objectMerger.computeMergeDelta(type, leftOid, rightOid, task, result); + + result.computeStatus(); + return objectDelta; + + } catch (ObjectNotFoundException | SchemaException | ConfigurationException | RuntimeException | Error e) { + result.recordFatalError(e); + throw e; + } + } + + @Override + public PrismObject mergeObjectsPreviewObject(Class type, String leftOid, + String rightOid, Task task, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException, ConfigurationException { + OperationResult result = parentResult.createMinorSubresult(MERGE_OBJECTS_PREVIEW_OBJECT); + + try { + + ObjectDelta objectDelta = objectMerger.computeMergeDelta(type, leftOid, rightOid, 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 | 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..4ee585510da --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ObjectMerger.java @@ -0,0 +1,272 @@ +/** + * 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.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.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.PrismContext; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismObjectDefinition; +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.path.ItemPath; +import com.evolveum.midpoint.schema.ObjectDeltaOperation; +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.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); + + @Autowired(required = true) + private ModelObjectResolver objectResolver; + + @Autowired(required = true) + private SystemObjectCache systemObjectCache; + + @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, Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, ConfigurationException, + ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, + PolicyViolationException, SecurityViolationException { + ObjectDelta objectDelta = computeMergeDelta(type, leftOid, rightOid, 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, + Task task, OperationResult result) + throws ObjectNotFoundException, SchemaException, ConfigurationException { + + 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 = systemConfiguration.asObjectable().getMergeConfiguration(); + 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, itemMergeConfig, itemPath); + 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) { + // TODO: We might need to check for super-paths here. + // E.g. if we have already processed metadata, we do not want to process + // metadata/modifyTimestamp + if (processedPath.equivalent(itemPath)) { + 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, defaultItemMergeConfig, itemPath); + } catch (SchemaException 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 { + throw new SystemException("Unexpected exception: "+te, te); + } + } + } + + return leftObjectDelta; + + } + + private ItemDelta mergeItem(PrismObject objectLeft, PrismObject objectRight, + ItemMergeConfigurationType itemMergeConfig, ItemPath itemPath) throws SchemaException { + 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(); + } + 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 right + if (itemRight == null) { + itemDelta.setValueToReplace(); + } else { + itemDelta.setValuesToReplace(itemRight.getClonedValues()); + } + return itemDelta; + } + } else { + if (rightStrategy == null || rightStrategy == MergeStategyType.IGNORE) { + // TAKE left, IGNORE right + return null; + } else { + // TAKE left, TAKE right + if (itemDefinition.isSingleValue()) { + if (itemLeft == null) { + itemDelta.setValuesToReplace(itemRight.getClonedValues()); + return itemDelta; + } else if (itemRight != null) { + throw new SchemaException("Attempt to put multiple values in a single-valued item "+itemPath); + } else { + return null; + } + } else { + itemDelta.addValuesToAdd(itemRight.getClonedValues()); + return itemDelta; + } + } + } + } + +} 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..c0d48bad3f4 --- /dev/null +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMerge.java @@ -0,0 +1,242 @@ +/* + * 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.util.PrismAsserts; +import com.evolveum.midpoint.prism.util.PrismTestUtil; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.test.util.TestUtil; +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"); + + @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"); + } + + @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(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + ObjectDelta delta = + modelInteractionService.mergeObjectsPreviewDelta(UserType.class, USER_JACK_OID, USER_GUYBRUSH_OID, 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, + PrismTestUtil.createPolyString(USER_GUYBRUSH_FULL_NAME)); + PrismAsserts.assertPropertyReplace(delta, UserType.F_ADDITIONAL_NAME); + PrismAsserts.assertPropertyReplace(delta, UserType.F_LOCALITY, + PrismTestUtil.createPolyString(USER_GUYBRUSH_LOCALITY)); + PrismAsserts.assertPropertyAdd(delta, UserType.F_EMPLOYEE_TYPE, + "SAILOR", "PIRATE WANNABE"); + + } + + @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, 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, PrismTestUtil.createPolyString(USER_JACK_USERNAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_GIVEN_NAME, PrismTestUtil.createPolyString(USER_JACK_GIVEN_NAME)); + PrismAsserts.assertNoItem(object, UserType.F_FAMILY_NAME); + PrismAsserts.assertPropertyValue(object, + UserType.F_FULL_NAME, PrismTestUtil.createPolyString(USER_GUYBRUSH_FULL_NAME)); + PrismAsserts.assertNoItem(object, UserType.F_ADDITIONAL_NAME); + PrismAsserts.assertPropertyValue(object, + UserType.F_LOCALITY, PrismTestUtil.createPolyString(USER_GUYBRUSH_LOCALITY)); + PrismAsserts.assertPropertyValue(object, + UserType.F_EMPLOYEE_TYPE, USER_JACK_EMPLOYEE_TYPE, "SAILOR", "PIRATE WANNABE"); + + } + + @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, 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, + PrismTestUtil.createPolyString(USER_JACK_FULL_NAME)); + PrismAsserts.assertPropertyReplace(delta, UserType.F_ADDITIONAL_NAME, + PrismTestUtil.createPolyString(USER_JACK_ADDITIONAL_NAME)); + PrismAsserts.assertPropertyReplace(delta, UserType.F_LOCALITY, + PrismTestUtil.createPolyString(USER_JACK_LOCALITY)); + PrismAsserts.assertPropertyAdd(delta, UserType.F_EMPLOYEE_TYPE, + USER_JACK_EMPLOYEE_TYPE); + + } + + @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, 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, PrismTestUtil.createPolyString(USER_GUYBRUSH_USERNAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_GIVEN_NAME, PrismTestUtil.createPolyString(USER_GUYBRUSH_GIVEN_NAME)); + PrismAsserts.assertNoItem(object, UserType.F_FAMILY_NAME); + PrismAsserts.assertPropertyValue(object, + UserType.F_FULL_NAME, PrismTestUtil.createPolyString(USER_JACK_FULL_NAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_ADDITIONAL_NAME, PrismTestUtil.createPolyString(USER_JACK_ADDITIONAL_NAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_LOCALITY, PrismTestUtil.createPolyString(USER_JACK_LOCALITY)); + PrismAsserts.assertPropertyValue(object, + UserType.F_EMPLOYEE_TYPE, USER_JACK_EMPLOYEE_TYPE, "SAILOR", "PIRATE WANNABE"); + + } + + @Test + public void test200MergeJackGuybrush() throws Exception { + final String TEST_NAME = "test200MergeJackGuybrush"; + 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, 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, PrismTestUtil.createPolyString(USER_JACK_USERNAME)); + PrismAsserts.assertPropertyValue(object, + UserType.F_GIVEN_NAME, PrismTestUtil.createPolyString(USER_JACK_GIVEN_NAME)); + PrismAsserts.assertNoItem(object, UserType.F_FAMILY_NAME); + PrismAsserts.assertPropertyValue(object, + UserType.F_FULL_NAME, PrismTestUtil.createPolyString(USER_GUYBRUSH_FULL_NAME)); + PrismAsserts.assertNoItem(object, UserType.F_ADDITIONAL_NAME); + PrismAsserts.assertPropertyValue(object, + UserType.F_LOCALITY, PrismTestUtil.createPolyString(USER_GUYBRUSH_LOCALITY)); + PrismAsserts.assertPropertyValue(object, + UserType.F_EMPLOYEE_TYPE, USER_JACK_EMPLOYEE_TYPE, "SAILOR", "PIRATE WANNABE"); + + assertNoObject(UserType.class, USER_GUYBRUSH_OID); + + } +} 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..93f7741d057 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,31 @@ Jamaica + + default + + name + take + + + givenName + take + ignore + + + familyName + + + fullName + take + + + employeeType + take + 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 @@ + From 48c2cb2d4347af310f826d8c42176367723e2c1e Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Tue, 11 Oct 2016 16:42:36 +0200 Subject: [PATCH 06/15] Test comments --- .../evolveum/midpoint/model/intest/TestMerge.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 index c0d48bad3f4..9212870d3cf 100644 --- 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 @@ -52,6 +52,9 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti "SAILOR", "PIRATE WANNABE"); } + /** + * MID-3460 + */ @Test public void test100MergeJackGuybrushPreviewDelta() throws Exception { final String TEST_NAME = "test100MergeJackGuybrushPreviewDelta"; @@ -87,6 +90,9 @@ public void test100MergeJackGuybrushPreviewDelta() throws Exception { } + /** + * MID-3460 + */ @Test public void test102MergeJackGuybrushPreviewObject() throws Exception { final String TEST_NAME = "test102MergeJackGuybrushPreviewObject"; @@ -123,6 +129,9 @@ public void test102MergeJackGuybrushPreviewObject() throws Exception { } + /** + * MID-3460 + */ @Test public void test110MergeGuybrushJackPreviewDelta() throws Exception { final String TEST_NAME = "test110MergeGuybrushJackPreviewDelta"; @@ -165,6 +174,9 @@ public void test110MergeGuybrushJackPreviewDelta() throws Exception { } + /** + * MID-3460 + */ @Test public void test112MergeGuybrushJackPreviewObject() throws Exception { final String TEST_NAME = "test112MergeGuybrushJackPreviewObject"; @@ -202,6 +214,9 @@ public void test112MergeGuybrushJackPreviewObject() throws Exception { } + /** + * MID-3460 + */ @Test public void test200MergeJackGuybrush() throws Exception { final String TEST_NAME = "test200MergeJackGuybrush"; From 1336bd75c6ba6ae7f6a2435c3a260dc26428ea2b Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Tue, 11 Oct 2016 19:09:46 +0200 Subject: [PATCH 07/15] Identity merge, second step (MID-3460) --- .../midpoint/prism/util/PrismAsserts.java | 54 +++++++++-- .../evolveum/midpoint/prism/TestCompare.java | 2 +- .../midpoint/schema/util/FocusTypeUtil.java | 47 ++++++++++ .../midpoint/schema/TestParseDiffPatch.java | 4 +- .../midpoint/test/util/MidPointAsserts.java | 23 +++++ .../model/impl/controller/ObjectMerger.java | 33 ++++++- .../midpoint/model/intest/TestMerge.java | 92 +++++++++++++++---- .../resources/common/system-configuration.xml | 22 +++++ .../test/AbstractModelIntegrationTest.java | 14 +-- .../test/AbstractIntegrationTest.java | 10 ++ 10 files changed, 264 insertions(+), 37 deletions(-) create mode 100644 infra/schema/src/main/java/com/evolveum/midpoint/schema/util/FocusTypeUtil.java 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 421a62ecdf8..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 @@ -428,11 +428,11 @@ public static void assertNoItemDelta(ObjectDelta objectDelta, ItemPath itemPa 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"; @@ -441,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"; @@ -454,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/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/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-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 index 4ee585510da..e65fcf408f8 100644 --- 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 @@ -28,14 +28,17 @@ 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.PrismObjectDefinition; +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.path.ItemPath; +import com.evolveum.midpoint.prism.path.ItemPath.CompareResult; import com.evolveum.midpoint.schema.ObjectDeltaOperation; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; @@ -157,10 +160,11 @@ public void visit(Visitable visitable) { boolean found = false; for (ItemPath processedPath: processedPaths) { - // TODO: We might need to check for super-paths here. + // Need to check for super-paths here. // E.g. if we have already processed metadata, we do not want to process // metadata/modifyTimestamp - if (processedPath.equivalent(itemPath)) { + CompareResult compareResult = processedPath.compareComplex(itemPath); + if (compareResult == CompareResult.EQUIVALENT || compareResult == CompareResult.SUBPATH) { found = true; break; } @@ -225,6 +229,11 @@ private ItemDelta mergeItem(PrismObject ItemDelta mergeItem(PrismObject valuesRight = itemRight.getValues(); + for (PrismValue valueRight: valuesRight) { + if (!itemLeft.containsEquivalentValue(valueRight)) { + PrismValue clonedValue = valueRight.clone(); + if (clonedValue instanceof PrismContainerValue) { + ((PrismContainerValue)clonedValue).setId(null); + } + itemDelta.addValueToAdd(clonedValue); + } + } + return itemDelta; + } } } } 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 index 9212870d3cf..43e0bc761a2 100644 --- 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 @@ -27,11 +27,15 @@ 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.prism.util.PrismTestUtil; 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.MetadataType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; /** @@ -50,6 +54,18 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti 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("Scurvy Seadogs")); + 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("Scurvy Seadogs")); + 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); } /** @@ -62,7 +78,13 @@ public void test100MergeJackGuybrushPreviewDelta() throws Exception { 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 = @@ -81,12 +103,21 @@ public void test100MergeJackGuybrushPreviewDelta() throws Exception { PrismAsserts.assertNoItemDelta(delta, UserType.F_GIVEN_NAME); PrismAsserts.assertPropertyReplace(delta, UserType.F_FAMILY_NAME); PrismAsserts.assertPropertyReplace(delta, UserType.F_FULL_NAME, - PrismTestUtil.createPolyString(USER_GUYBRUSH_FULL_NAME)); + createPolyString(USER_GUYBRUSH_FULL_NAME)); PrismAsserts.assertPropertyReplace(delta, UserType.F_ADDITIONAL_NAME); PrismAsserts.assertPropertyReplace(delta, UserType.F_LOCALITY, - PrismTestUtil.createPolyString(USER_GUYBRUSH_LOCALITY)); + createPolyString(USER_GUYBRUSH_LOCALITY)); PrismAsserts.assertPropertyAdd(delta, UserType.F_EMPLOYEE_TYPE, "SAILOR", "PIRATE WANNABE"); + PrismAsserts.assertPropertyAdd(delta, UserType.F_ORGANIZATION, + createPolyString("Pirate Wannabes")); + 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)); } @@ -115,18 +146,23 @@ public void test102MergeJackGuybrushPreviewObject() throws Exception { assertEquals("Wrong object OID", USER_JACK_OID, object.getOid()); PrismAsserts.assertPropertyValue(object, - UserType.F_NAME, PrismTestUtil.createPolyString(USER_JACK_USERNAME)); + UserType.F_NAME, createPolyString(USER_JACK_USERNAME)); PrismAsserts.assertPropertyValue(object, - UserType.F_GIVEN_NAME, PrismTestUtil.createPolyString(USER_JACK_GIVEN_NAME)); + UserType.F_GIVEN_NAME, createPolyString(USER_JACK_GIVEN_NAME)); PrismAsserts.assertNoItem(object, UserType.F_FAMILY_NAME); PrismAsserts.assertPropertyValue(object, - UserType.F_FULL_NAME, PrismTestUtil.createPolyString(USER_GUYBRUSH_FULL_NAME)); + UserType.F_FULL_NAME, createPolyString(USER_GUYBRUSH_FULL_NAME)); PrismAsserts.assertNoItem(object, UserType.F_ADDITIONAL_NAME); PrismAsserts.assertPropertyValue(object, - UserType.F_LOCALITY, PrismTestUtil.createPolyString(USER_GUYBRUSH_LOCALITY)); + 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("Scurvy Seadogs"), createPolyString("Pirate Wannabes")); + assertAssignedRoles(object, ROLE_SAILOR_OID, ROLE_EMPTY_OID, ROLE_THIEF_OID, + ROLE_PIRATE_OID, ROLE_NICE_PIRATE_OID); } /** @@ -164,13 +200,24 @@ public void test110MergeGuybrushJackPreviewDelta() throws Exception { PrismAsserts.assertNoItemDelta(delta, UserType.F_GIVEN_NAME); PrismAsserts.assertPropertyReplace(delta, UserType.F_FAMILY_NAME); PrismAsserts.assertPropertyReplace(delta, UserType.F_FULL_NAME, - PrismTestUtil.createPolyString(USER_JACK_FULL_NAME)); + createPolyString(USER_JACK_FULL_NAME)); PrismAsserts.assertPropertyReplace(delta, UserType.F_ADDITIONAL_NAME, - PrismTestUtil.createPolyString(USER_JACK_ADDITIONAL_NAME)); + createPolyString(USER_JACK_ADDITIONAL_NAME)); PrismAsserts.assertPropertyReplace(delta, UserType.F_LOCALITY, - PrismTestUtil.createPolyString(USER_JACK_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")); + 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)); + } @@ -199,18 +246,24 @@ public void test112MergeGuybrushJackPreviewObject() throws Exception { assertEquals("Wrong object OID", USER_GUYBRUSH_OID, object.getOid()); PrismAsserts.assertPropertyValue(object, - UserType.F_NAME, PrismTestUtil.createPolyString(USER_GUYBRUSH_USERNAME)); + UserType.F_NAME, createPolyString(USER_GUYBRUSH_USERNAME)); PrismAsserts.assertPropertyValue(object, - UserType.F_GIVEN_NAME, PrismTestUtil.createPolyString(USER_GUYBRUSH_GIVEN_NAME)); + UserType.F_GIVEN_NAME, createPolyString(USER_GUYBRUSH_GIVEN_NAME)); PrismAsserts.assertNoItem(object, UserType.F_FAMILY_NAME); PrismAsserts.assertPropertyValue(object, - UserType.F_FULL_NAME, PrismTestUtil.createPolyString(USER_JACK_FULL_NAME)); + UserType.F_FULL_NAME, createPolyString(USER_JACK_FULL_NAME)); PrismAsserts.assertPropertyValue(object, - UserType.F_ADDITIONAL_NAME, PrismTestUtil.createPolyString(USER_JACK_ADDITIONAL_NAME)); + UserType.F_ADDITIONAL_NAME, createPolyString(USER_JACK_ADDITIONAL_NAME)); PrismAsserts.assertPropertyValue(object, - UserType.F_LOCALITY, PrismTestUtil.createPolyString(USER_JACK_LOCALITY)); + 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("Scurvy Seadogs"), createPolyString("Pirate Wannabes")); + + assertAssignedRoles(object, ROLE_SAILOR_OID, ROLE_EMPTY_OID, ROLE_THIEF_OID, + ROLE_PIRATE_OID, ROLE_NICE_PIRATE_OID); } @@ -239,18 +292,21 @@ public void test200MergeJackGuybrush() throws Exception { assertEquals("Wrong object OID", USER_JACK_OID, object.getOid()); PrismAsserts.assertPropertyValue(object, - UserType.F_NAME, PrismTestUtil.createPolyString(USER_JACK_USERNAME)); + UserType.F_NAME, createPolyString(USER_JACK_USERNAME)); PrismAsserts.assertPropertyValue(object, - UserType.F_GIVEN_NAME, PrismTestUtil.createPolyString(USER_JACK_GIVEN_NAME)); + UserType.F_GIVEN_NAME, createPolyString(USER_JACK_GIVEN_NAME)); PrismAsserts.assertNoItem(object, UserType.F_FAMILY_NAME); PrismAsserts.assertPropertyValue(object, - UserType.F_FULL_NAME, PrismTestUtil.createPolyString(USER_GUYBRUSH_FULL_NAME)); + UserType.F_FULL_NAME, createPolyString(USER_GUYBRUSH_FULL_NAME)); PrismAsserts.assertNoItem(object, UserType.F_ADDITIONAL_NAME); PrismAsserts.assertPropertyValue(object, - UserType.F_LOCALITY, PrismTestUtil.createPolyString(USER_GUYBRUSH_LOCALITY)); + 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/resources/common/system-configuration.xml b/model/model-intest/src/test/resources/common/system-configuration.xml index 93f7741d057..bf470baba22 100644 --- a/model/model-intest/src/test/resources/common/system-configuration.xml +++ b/model/model-intest/src/test/resources/common/system-configuration.xml @@ -207,6 +207,28 @@ take take + + organization + take + take + + + organizationalUnit + take + + + activation + take + + + assignment + take + take + + + linkRef + take + take 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); + } } From 1c609dd4ef4e7b67d1b13bf5b3d8963489c16159 Mon Sep 17 00:00:00 2001 From: honchar Date: Wed, 12 Oct 2016 07:07:57 +0200 Subject: [PATCH 08/15] role catalog styles + restructuring --- .../assignment/CatalogItemsPanel.java | 4 +- .../web/component/data/MultiButtonTable.html | 37 ++--- .../web/component/data/MultiButtonTable.java | 135 +++++++++++++----- .../localization/Midpoint.properties | 4 +- .../localization/Midpoint_en.properties | 2 + .../src/main/webapp/less/midpoint-theme.less | 6 + 6 files changed, 129 insertions(+), 59 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java index 2b043445186..b62b3445164 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java @@ -152,7 +152,7 @@ private void initLayout() { initCartButton(headerPanel); initSearchPanel(headerPanel); - MultiButtonTable assignmentsTable = new MultiButtonTable(ID_MULTI_BUTTON_TABLE, itemsPerRow, itemsListModel); + MultiButtonTable assignmentsTable = new MultiButtonTable(ID_MULTI_BUTTON_TABLE, itemsPerRow, itemsListModel, pageBase); assignmentsTable.setOutputMarkupId(true); add(assignmentsTable); @@ -327,7 +327,7 @@ private void refreshItemsPanel() { long from = currentPage * itemsPerRow * DEFAULT_ROWS_COUNT; provider.internalIterator(from, itemsPerRow * DEFAULT_ROWS_COUNT); } - MultiButtonTable assignmentsTable = new MultiButtonTable(ID_MULTI_BUTTON_TABLE, itemsPerRow, itemsListModel); + MultiButtonTable assignmentsTable = new MultiButtonTable(ID_MULTI_BUTTON_TABLE, itemsPerRow, itemsListModel, pageBase); assignmentsTable.setOutputMarkupId(true); replace(assignmentsTable); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.html index 8b7d500949e..a4ec9adbc41 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.html @@ -20,23 +20,26 @@
-
-
-

-
-
- -
- +
+
+ +
+
+
+
+ +
+ +
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java index badd7882a24..9bf6cd11e15 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java @@ -16,6 +16,9 @@ package com.evolveum.midpoint.web.component.data; 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.web.component.AjaxIconButton; import com.evolveum.midpoint.web.component.assignment.*; import com.evolveum.midpoint.web.page.self.PageAssignmentDetails; import com.evolveum.midpoint.web.session.UsersStorage; @@ -29,6 +32,7 @@ import org.apache.wicket.markup.html.navigation.paging.IPageableItems; import org.apache.wicket.markup.repeater.RepeatingView; import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; import java.util.ArrayList; import java.util.List; @@ -41,14 +45,22 @@ public class MultiButtonTable extends BasePanel> { private static final String ID_ROW = "row"; private static final String ID_CELL = "cell"; + private static final String ID_ITEM_BUTTON_CONTAINER = "itemButtonContainer"; private static final String ID_INNER = "inner"; private static final String ID_INNER_LABEL = "innerLabel"; private static final String ID_TYPE_ICON = "typeIcon"; private static final String ID_ADD_TO_CART_LINK = "addToCartLink"; + private static final String ID_ADD_TO_CART_LINK_LABEL = "addToCartLinkLabel"; + private static final String ID_ADD_TO_CART_LINK_ICON = "addToCartLinkIcon"; private static final String ID_DETAILS_LINK = "detailsLink"; + private static final String ID_DETAILS_LINK_LABEL = "detailsLinkLabel"; + private static final String ID_DETAILS_LINK_ICON = "detailsLinkIcon"; + private String addToCartLinkIcon = "fa fa-times-circle fa-lg text-danger"; + private String detailsLinkIcon = "fa fa-arrow-circle-right"; private long itemsCount = 0; private long itemsPerRow = 0; + private PageBase pageBase; private boolean plusIconClicked = false; @@ -56,9 +68,10 @@ public MultiButtonTable (String id){ super(id); } - public MultiButtonTable (String id, long itemsPerRow, IModel> model){ + public MultiButtonTable (String id, long itemsPerRow, IModel> model, PageBase pageBase){ super(id, model); this.itemsPerRow = itemsPerRow; + this.pageBase = pageBase; initLayout(); } @@ -82,7 +95,11 @@ private void initLayout(){ WebMarkupContainer colContainer = new WebMarkupContainer(columns.newChildId()); columns.add(colContainer); - populateCell(colContainer, assignmentsList.get(index)); + WebMarkupContainer itemButtonContainer = new WebMarkupContainer(ID_ITEM_BUTTON_CONTAINER); + itemButtonContainer.setOutputMarkupId(true); + itemButtonContainer.add(new AttributeAppender("class", getBackgroundClass(assignmentsList.get(index).getType()))); + colContainer.add(itemButtonContainer); + populateCell(itemButtonContainer, assignmentsList.get(index)); index++; if (index >= assignmentsList.size()){ break; @@ -100,58 +117,63 @@ protected void populateCell(WebMarkupContainer cellContainer, final AssignmentEd @Override public void onClick(AjaxRequestTarget ajaxRequestTarget) { - if (!plusIconClicked) { - IModel assignmentModel = new IModel() { - @Override - public AssignmentEditorDto getObject() { - assignment.setMinimized(false); - assignment.setSimpleView(true); - return assignment; - } - - @Override - public void setObject(AssignmentEditorDto assignmentEditorDto) { - - } - - @Override - public void detach() { - - } - }; - setResponsePage(new PageAssignmentDetails(assignmentModel)); - } else { - plusIconClicked = false; - } + assignmentDetailsPerformed(assignment, ajaxRequestTarget); } }; cellContainer.add(inner); Label nameLabel = new Label(ID_INNER_LABEL, assignment.getName()); inner.add(nameLabel); - - AjaxLink detailsLink = new AjaxLink(ID_DETAILS_LINK) { - private static final long serialVersionUID = 1L; - @Override - public void onClick(AjaxRequestTarget target) { - // TODO - } - + AjaxLink detailsLink = new AjaxLink(ID_DETAILS_LINK) { + @Override + public void onClick(AjaxRequestTarget ajaxRequestTarget) { + assignmentDetailsPerformed(assignment, ajaxRequestTarget); + } }; cellContainer.add(detailsLink); - - AjaxLink addToCartLink = new AjaxLink(ID_ADD_TO_CART_LINK) { + + Label detailsLinkLabel = new Label(ID_DETAILS_LINK_LABEL, pageBase.createStringResource("MultiButtonPanel.detailsLink")); + detailsLinkLabel.setRenderBodyOnly(true); + detailsLink.add(detailsLinkLabel); + + AjaxLink detailsLinkIcon = new AjaxLink(ID_DETAILS_LINK_ICON) { private static final long serialVersionUID = 1L; @Override public void onClick(AjaxRequestTarget target) { - addAssignmentPerformed(assignment, target); } - + + }; + detailsLink.add(detailsLinkIcon); + + AjaxLink addToCartLink = new AjaxLink(ID_ADD_TO_CART_LINK) { + @Override + public void onClick(AjaxRequestTarget ajaxRequestTarget) { + addAssignmentPerformed(assignment, ajaxRequestTarget); + } }; cellContainer.add(addToCartLink); - + +// Label addToCartLinkLabel = new Label(ID_ADD_TO_CART_LINK_LABEL, pageBase.createStringResource("MultiButtonPanel.addToCartLink")); +// addToCartLinkLabel.setRenderBodyOnly(true); +// addToCartLinkLabel.add(new AjaxEventBehavior("click") { +// @Override +// protected void onEvent(AjaxRequestTarget ajaxRequestTarget) { +// addAssignmentPerformed(assignment, ajaxRequestTarget); +// } +// }); +// addToCartLink.add(addToCartLinkLabel); + + AjaxLink addToCartLinkIcon = new AjaxLink(ID_ADD_TO_CART_LINK_ICON) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + } + + }; + addToCartLink.add(addToCartLinkIcon); WebMarkupContainer icon = new WebMarkupContainer(ID_TYPE_ICON); icon.add(new AttributeAppender("class", getIconClass(assignment.getType()))); @@ -159,7 +181,30 @@ public void onClick(AjaxRequestTarget target) { } - protected void assignmentDetailsPerformed(AjaxRequestTarget target){ + private void assignmentDetailsPerformed(final AssignmentEditorDto assignment, AjaxRequestTarget target){ + if (!plusIconClicked) { + IModel assignmentModel = new IModel() { + @Override + public AssignmentEditorDto getObject() { + assignment.setMinimized(false); + assignment.setSimpleView(true); + return assignment; + } + + @Override + public void setObject(AssignmentEditorDto assignmentEditorDto) { + + } + + @Override + public void detach() { + + } + }; + setResponsePage(new PageAssignmentDetails(assignmentModel)); + } else { + plusIconClicked = false; + } } private String getIconClass(AssignmentEditorDtoType type){ @@ -175,6 +220,18 @@ private String getIconClass(AssignmentEditorDtoType type){ } } + private String getBackgroundClass(AssignmentEditorDtoType type){ + if (AssignmentEditorDtoType.ROLE.equals(type)){ + return "object-role-bg"; + }else if (AssignmentEditorDtoType.SERVICE.equals(type)){ + return "object-service-bg"; + }else if (AssignmentEditorDtoType.ORG_UNIT.equals(type)){ + return "object-org-bg"; + } else { + return ""; + } + } + private void addAssignmentPerformed(AssignmentEditorDto assignment, AjaxRequestTarget target){ plusIconClicked = true; UsersStorage storage = getPageBase().getSessionStorage().getUsers(); diff --git a/gui/admin-gui/src/main/resources/localization/Midpoint.properties b/gui/admin-gui/src/main/resources/localization/Midpoint.properties index 51ebcb9edab..a1b07aaba23 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 @@ -3348,4 +3350,4 @@ PageAuditLogViewer.column.time=Time PageAuditLogViewer.column.initiatorRef=Initiator PageAuditLogViewer.column.taskIdentifier=Task Identifier PageAuditLogViewer.column.channel=Channel -PageAuditLogViewer.column.delta=Delta \ No newline at end of file +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..5aacb90d486 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 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..0027243b94d 100644 --- a/gui/admin-gui/src/main/webapp/less/midpoint-theme.less +++ b/gui/admin-gui/src/main/webapp/less/midpoint-theme.less @@ -1091,6 +1091,12 @@ dd.stacktrace::before { .inner { min-height: 90px; } + + .inner-label { + font-size: 18px; + padding-top: 15px; + padding-left: 10px; + } } .shopping-cart-item-box-footer { From 1c52f5a161504f0d8abdc8491519dcda4185d368 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 12 Oct 2016 11:18:51 +0200 Subject: [PATCH 09/15] Fixing orgstruct tests --- .../midpoint/model/intest/orgstruct/TestOrgStruct.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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); From 21f8052f6565e607513404ab1f8eb405ddda19c3 Mon Sep 17 00:00:00 2001 From: ozkanbayraktar Date: Wed, 12 Oct 2016 11:18:56 +0200 Subject: [PATCH 10/15] AuditSearchDto.java is added to the reports dto --- .../admin/reports/PageAuditLogViewer.html | 12 +- .../admin/reports/PageAuditLogViewer.java | 27 +-- .../reports/dto/AuditEventRecordProvider.java | 5 - .../admin/reports/dto/AuditSearchDto.java | 174 ++++++++++++++++++ 4 files changed, 192 insertions(+), 26 deletions(-) create mode 100644 gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/dto/AuditSearchDto.java diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.html index 6902a4cee8b..ccc66c1f329 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.html @@ -34,22 +34,18 @@
- - -
-
- -
+ + - -
+ +
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java index f612f769bb9..45856b11e1d 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageAuditLogViewer.java @@ -1,6 +1,7 @@ package com.evolveum.midpoint.web.page.admin.reports; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -20,6 +21,7 @@ import com.evolveum.midpoint.audit.api.AuditEventRecord; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.web.application.AuthorizationAction; import com.evolveum.midpoint.web.application.PageDescriptor; @@ -36,6 +38,8 @@ import com.evolveum.midpoint.web.page.admin.reports.dto.AuditSearchDto; import com.evolveum.midpoint.web.session.UserProfileStorage; import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventRecordType; +import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventStageType; +import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventTypeType; /** * Created by honchar. @@ -61,12 +65,11 @@ public class PageAuditLogViewer extends PageBase{ private static final String ID_CHANNEL = "channelField"; private static final String ID_HOST_IDENTIFIER = "hostIdentifierField"; private static final String ID_TARGET_NAME = "targetNameField"; - private static final String ID_TARGET_TYPE = "targetTypeField"; private static final String ID_TARGET_OWNER_NAME = "targetOwnerNameField"; private static final String ID_EVENT_TYPE = "eventTypeField"; private static final String ID_EVENT_STAGE = "eventStageField"; private static final String ID_OUTCOME = "outcomeField"; - + private static final String ID_MAIN_FORM = "mainForm"; private static final String ID_SEARCH_BUTTON = "searchButton"; @@ -148,13 +151,6 @@ private void initParametersPanel(Form mainForm){ targetName.setOutputMarkupId(true); parametersPanel.add(targetName); - IModel targetTypeModel = new PropertyModel<>(auditSearchDto, AuditSearchDto.F_TARGET_TYPE); - TextPanel targetType = new TextPanel(ID_TARGET_TYPE, targetTypeModel); - targetType.getBaseFormComponent().add(new EmptyOnChangeAjaxFormUpdatingBehavior()); - targetType.getBaseFormComponent().add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); - targetType.setOutputMarkupId(true); - parametersPanel.add(targetType); - IModel targetOwnerNameModel = new PropertyModel<>(auditSearchDto, AuditSearchDto.F_TARGET_OWNER_NAME); TextPanel targetOwnerName = new TextPanel(ID_TARGET_OWNER_NAME, targetOwnerNameModel); targetOwnerName.getBaseFormComponent().add(new EmptyOnChangeAjaxFormUpdatingBehavior()); @@ -162,22 +158,28 @@ private void initParametersPanel(Form mainForm){ targetOwnerName.setOutputMarkupId(true); parametersPanel.add(targetOwnerName); + IModel eventTypeListModel = new ListModel(Arrays.asList(AuditEventTypeType.values())); IModel eventTypeModel = new PropertyModel<>(auditSearchDto, AuditSearchDto.F_EVENT_TYPE); - TextPanel eventType = new TextPanel(ID_EVENT_TYPE, eventTypeModel); + DropDownChoicePanel eventType = new DropDownChoicePanel(ID_EVENT_TYPE, eventTypeModel, eventTypeListModel); + // TextPanel eventType = new TextPanel(ID_EVENT_TYPE, eventTypeModel); eventType.getBaseFormComponent().add(new EmptyOnChangeAjaxFormUpdatingBehavior()); eventType.getBaseFormComponent().add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); eventType.setOutputMarkupId(true); parametersPanel.add(eventType); + IModel eventStageListModel = new ListModel(Arrays.asList(AuditEventStageType.values())); IModel eventStageModel = new PropertyModel<>(auditSearchDto, AuditSearchDto.F_EVENT_STAGE); - TextPanel eventStage = new TextPanel(ID_EVENT_STAGE, eventStageModel); + DropDownChoicePanel eventStage = new DropDownChoicePanel(ID_EVENT_STAGE, eventStageModel, eventStageListModel); + // TextPanel eventStage = new TextPanel(ID_EVENT_STAGE, eventStageModel); eventStage.getBaseFormComponent().add(new EmptyOnChangeAjaxFormUpdatingBehavior()); eventStage.getBaseFormComponent().add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); eventStage.setOutputMarkupId(true); parametersPanel.add(eventStage); + IModel outcomeListModel = new ListModel(Arrays.asList(OperationResultStatus.values())); IModel outcomeModel = new PropertyModel<>(auditSearchDto, AuditSearchDto.F_OUTCOME); - TextPanel outcome = new TextPanel(ID_OUTCOME, outcomeModel); + // TextPanel outcome = new TextPanel(ID_OUTCOME, outcomeModel); + DropDownChoicePanel outcome = new DropDownChoicePanel(ID_OUTCOME, outcomeModel, outcomeListModel); outcome.getBaseFormComponent().add(new EmptyOnChangeAjaxFormUpdatingBehavior()); outcome.getBaseFormComponent().add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); outcome.setOutputMarkupId(true); @@ -223,7 +225,6 @@ public Map getParameters() { parameters.put("channel", auditSearchDto.getObject().getChannel()); parameters.put("hostIdentifier", auditSearchDto.getObject().getHostIdentifier()); parameters.put("targetName", auditSearchDto.getObject().getTargetName()); - parameters.put("targetType", auditSearchDto.getObject().getTargetType()); parameters.put("targetOwnerName", auditSearchDto.getObject().getTargetOwnerName()); parameters.put("eventType", auditSearchDto.getObject().getEventType()); parameters.put("eventStage", auditSearchDto.getObject().getEventStage()); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/dto/AuditEventRecordProvider.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/dto/AuditEventRecordProvider.java index bb78439c36a..4ea1f7df5d3 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/dto/AuditEventRecordProvider.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/dto/AuditEventRecordProvider.java @@ -163,11 +163,6 @@ private String generateFullQuery(String query, boolean orderBy){ } else { queryParameters.remove("hostIdentifier"); } - if (queryParameters.get("targetType") != null) { - query += "(aer.targetType = :targetType) and "; - } else { - queryParameters.remove("targetType"); - } if (queryParameters.get("targetOwnerName") != null) { query += "(aer.targetOwnerName = :targetOwnerName) and "; } else { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/dto/AuditSearchDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/dto/AuditSearchDto.java new file mode 100644 index 00000000000..c5bc7f22a77 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/dto/AuditSearchDto.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2010-2013 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.page.admin.reports.dto; + +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.Date; + +import com.evolveum.midpoint.audit.api.AuditEventType; +import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ExportType; + +import javax.xml.datatype.XMLGregorianCalendar; + +/** + * TODO - get rid of XMLGregorianCalendar - Date conversions + * + * @author lazyman + */ +public class AuditSearchDto implements Serializable { + + public static final String F_FROM_GREG = "fromGreg"; + public static final String F_TO_GREG = "toGreg"; + public static final String F_FROM = "from"; + public static final String F_TO = "to"; + public static final String F_INITIATOR_NAME = "initiatorName"; + public static final String F_CHANNEL = "channel"; + public static final String F_HOST_IDENTIFIER = "hostIdentifier"; + public static final String F_TARGET_NAME = "targetName"; + public static final String F_TARGET_OWNER_NAME = "targetOwnerName"; + public static final String F_EVENT_TYPE = "eventType"; + public static final String F_EVENT_STAGE = "eventStage"; + public static final String F_OUTCOME = "outcome"; + + private XMLGregorianCalendar fromGreg; + private XMLGregorianCalendar toGreg; + private Date from; + private Date to; + private String initiatorName; + private String channel; + private String hostIdentifier; + private String targetName; + private String targetOwnerName; + private String eventType; + private String eventStage; + private String outcome; + + public XMLGregorianCalendar getFromGreg() { + return MiscUtil.asXMLGregorianCalendar(from); + } + + public void setFromGreg(XMLGregorianCalendar fromGreg) { + this.from = MiscUtil.asDate(fromGreg); + this.fromGreg = fromGreg; + } + + public XMLGregorianCalendar getToGreg() { + return MiscUtil.asXMLGregorianCalendar(to); + } + + public void setToGreg(XMLGregorianCalendar toGreg) { + this.to = MiscUtil.asDate(toGreg); + this.toGreg = toGreg; + } + + public Date getFrom() { + if (from == null) { + from = new Date(); + } + return from; + } + + public void setFrom(Date from) { + this.from = from; + } + + public Date getTo() { + if (to == null) { + to = new Date(); + } + return to; + } + + public void setTo(Date to) { + this.to = to; + } + + public Timestamp getDateFrom() { + return new Timestamp(getFrom().getTime()); + } + + public Timestamp getDateTo() { + return new Timestamp(getTo().getTime()); + } + + public String getInitiatorName() { + return initiatorName; + } + + public void setInitiatorName(String initiatorName) { + this.initiatorName = initiatorName; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getHostIdentifier() { + return hostIdentifier; + } + + public void setHostIdentifier(String hostIdentifier) { + this.hostIdentifier = hostIdentifier; + } + + public String getTargetName() { + return targetName; + } + + public void setTargetName(String targetName) { + this.targetName = targetName; + } + + public String getTargetOwnerName() { + return targetOwnerName; + } + + public void setTargetOwnerName(String targetOwnerName) { + this.targetOwnerName = targetOwnerName; + } + + public String getEventType() { + return eventType; + } + + public void setEventType(String eventType) { + this.eventType = eventType; + } + + public String getEventStage() { + return eventStage; + } + + public void setEventStage(String eventStage) { + this.eventStage = eventStage; + } + + public String getOutcome() { + return outcome; + } + + public void setOutcome(String outcome) { + this.outcome = outcome; + } + +} From 3e586836f967a61d3491e740b8ceb520b4923507 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 12 Oct 2016 11:50:35 +0200 Subject: [PATCH 11/15] Support for multiple merge configurations (MID-3460) --- .../xml/ns/public/common/common-core-3.xsd | 50 +++++++++++++++---- .../model/api/ModelInteractionService.java | 4 +- .../midpoint/model/api/ModelService.java | 5 +- .../impl/controller/ModelController.java | 7 +-- .../ModelInteractionServiceImpl.java | 8 +-- .../model/impl/controller/ObjectMerger.java | 23 +++++++-- .../midpoint/model/intest/TestMerge.java | 19 ++++--- .../resources/common/system-configuration.xml | 19 +++++++ 8 files changed, 104 insertions(+), 31 deletions(-) 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 0bc7ca1ade5..49a7bef79a0 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 @@ -9378,12 +9378,10 @@ - + - Configuration for object merging. E.g. for merging two users. - Note: this is a single-valued item now. But it will most likely be - switched to multi-valued item in future midPoint versions. + Configurations for object merging. E.g. for merging two users. 3.5 @@ -12488,17 +12486,51 @@ - TODO + 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. + + + 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 5e0997e3fe9..bf4655d17a3 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 @@ -183,11 +183,11 @@ ConnectorOperationalStatus getConnectorOperationalStatus(String resourceOid, Ope throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException; ObjectDelta mergeObjectsPreviewDelta(Class type, - String leftOid, String rightOid, Task task, OperationResult result) + String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ConfigurationException; PrismObject mergeObjectsPreviewObject(Class type, - String leftOid, String rightOid, Task task, OperationResult result) + String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ConfigurationException; } 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 8f0a3b79ba4..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 @@ -664,10 +664,13 @@ CompareResultType compareObject(PrismObject object, * @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, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ConfigurationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, PolicyViolationException, SecurityViolationException; + 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 faa6ca60a33..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 @@ -2097,8 +2097,9 @@ public AccessCertificationCampaignType createCampaign(String definitionOid, Task //endregion @Override - public Collection> mergeObjects(Class type, String leftOid, String rightOid, Task task, - OperationResult parentResult) throws ObjectNotFoundException, SchemaException, ConfigurationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, PolicyViolationException, SecurityViolationException { + 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); @@ -2110,7 +2111,7 @@ public Collection> deltas = - objectMerger.mergeObjects(type, leftOid, rightOid, task, result); + objectMerger.mergeObjects(type, leftOid, rightOid, mergeConfigurationName, task, result); result.computeStatus(); return deltas; 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 4734e17af24..d1e924ea9ed 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 @@ -708,13 +708,13 @@ public ConnectorOperationalStatus getConnectorOperationalStatus(String resourceO @Override public ObjectDelta mergeObjectsPreviewDelta(Class type, String leftOid, - String rightOid, Task task, OperationResult parentResult) + String rightOid, String mergeConfigurationName, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, ConfigurationException { OperationResult result = parentResult.createMinorSubresult(MERGE_OBJECTS_PREVIEW_DELTA); try { - ObjectDelta objectDelta = objectMerger.computeMergeDelta(type, leftOid, rightOid, task, result); + ObjectDelta objectDelta = objectMerger.computeMergeDelta(type, leftOid, rightOid, mergeConfigurationName, task, result); result.computeStatus(); return objectDelta; @@ -727,13 +727,13 @@ public ObjectDelta mergeObjectsPreviewDelta(Class t @Override public PrismObject mergeObjectsPreviewObject(Class type, String leftOid, - String rightOid, Task task, OperationResult parentResult) + String rightOid, String mergeConfigurationName, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, ConfigurationException { OperationResult result = parentResult.createMinorSubresult(MERGE_OBJECTS_PREVIEW_OBJECT); try { - ObjectDelta objectDelta = objectMerger.computeMergeDelta(type, leftOid, rightOid, task, result); + ObjectDelta objectDelta = objectMerger.computeMergeDelta(type, leftOid, rightOid, mergeConfigurationName, task, result); final PrismObject objectLeft = objectResolver.getObjectSimple(type, leftOid, null, task, result).asPrismObject(); 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 index e65fcf408f8..ad80f036362 100644 --- 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 @@ -19,6 +19,7 @@ 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; @@ -31,7 +32,6 @@ import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.PrismValue; import com.evolveum.midpoint.prism.Visitable; import com.evolveum.midpoint.prism.Visitor; @@ -88,11 +88,11 @@ public class ObjectMerger { private ModelController modelController; public Collection> mergeObjects(Class type, - String leftOid, String rightOid, Task task, OperationResult result) + 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, task, result); + ObjectDelta objectDelta = computeMergeDelta(type, leftOid, rightOid, mergeConfigurationName, task, result); if (objectDelta != null && !objectDelta.isEmpty()) { Collection> executedDeltas = @@ -115,14 +115,14 @@ public Collection ObjectDelta computeMergeDelta(Class type, String leftOid, String rightOid, - Task task, OperationResult result) + String mergeConfigurationName, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ConfigurationException { 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 = systemConfiguration.asObjectable().getMergeConfiguration(); + MergeConfigurationType mergeConfiguration = selectConfiguration(systemConfiguration, mergeConfigurationName); if (mergeConfiguration == null) { throw new ConfigurationException("No merge configuration defined"); } @@ -294,4 +294,17 @@ private ItemDelta mergeItem(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/TestMerge.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMerge.java index 43e0bc761a2..7828aaf2b4e 100644 --- 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 @@ -29,13 +29,11 @@ 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.prism.util.PrismTestUtil; 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.MetadataType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; /** @@ -47,6 +45,8 @@ 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"; @Override public void initSystem(Task initTask, OperationResult initResult) throws Exception { @@ -88,7 +88,8 @@ public void test100MergeJackGuybrushPreviewDelta() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); ObjectDelta delta = - modelInteractionService.mergeObjectsPreviewDelta(UserType.class, USER_JACK_OID, USER_GUYBRUSH_OID, task, result); + modelInteractionService.mergeObjectsPreviewDelta(UserType.class, + USER_JACK_OID, USER_GUYBRUSH_OID, MERGE_CONFIG_DEFAULT_NAME, task, result); // THEN TestUtil.displayThen(TEST_NAME); @@ -135,7 +136,8 @@ public void test102MergeJackGuybrushPreviewObject() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); PrismObject object = - modelInteractionService.mergeObjectsPreviewObject(UserType.class, USER_JACK_OID, USER_GUYBRUSH_OID, task, result); + modelInteractionService.mergeObjectsPreviewObject(UserType.class, + USER_JACK_OID, USER_GUYBRUSH_OID, MERGE_CONFIG_DEFAULT_NAME, task, result); // THEN TestUtil.displayThen(TEST_NAME); @@ -185,7 +187,8 @@ public void test110MergeGuybrushJackPreviewDelta() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); ObjectDelta delta = - modelInteractionService.mergeObjectsPreviewDelta(UserType.class, USER_GUYBRUSH_OID, USER_JACK_OID, task, result); + modelInteractionService.mergeObjectsPreviewDelta(UserType.class, + USER_GUYBRUSH_OID, USER_JACK_OID, MERGE_CONFIG_DEFAULT_NAME, task, result); // THEN TestUtil.displayThen(TEST_NAME); @@ -235,7 +238,8 @@ public void test112MergeGuybrushJackPreviewObject() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); PrismObject object = - modelInteractionService.mergeObjectsPreviewObject(UserType.class, USER_GUYBRUSH_OID, USER_JACK_OID, task, result); + modelInteractionService.mergeObjectsPreviewObject(UserType.class, + USER_GUYBRUSH_OID, USER_JACK_OID, MERGE_CONFIG_DEFAULT_NAME, task, result); // THEN TestUtil.displayThen(TEST_NAME); @@ -280,7 +284,8 @@ public void test200MergeJackGuybrush() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); - modelService.mergeObjects(UserType.class, USER_JACK_OID, USER_GUYBRUSH_OID, task, result); + modelService.mergeObjects(UserType.class, + USER_JACK_OID, USER_GUYBRUSH_OID, MERGE_CONFIG_DEFAULT_NAME, task, result); // THEN TestUtil.displayThen(TEST_NAME); 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 bf470baba22..979c886a42f 100644 --- a/model/model-intest/src/test/resources/common/system-configuration.xml +++ b/model/model-intest/src/test/resources/common/system-configuration.xml @@ -184,6 +184,7 @@ Jamaica + default @@ -233,4 +234,22 @@ take + + + empty + + + + allRight + + take + + + + + allLeft + + take + + From 51c54399ae40e8c56477984ae1d998bd1b89a129 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 12 Oct 2016 13:05:51 +0200 Subject: [PATCH 12/15] Shopping cart styles update --- .../assignment/CatalogItemsPanel.html | 2 +- .../assignment/CatalogItemsPanel.java | 2 +- .../src/main/webapp/less/midpoint-theme.less | 19 +++++++++++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) 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 2c9666562f3..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 @@ -29,7 +29,7 @@ style="font-size: 10px; position: absolute; top: -1px; right: 50%;">
-
+
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java index b62b3445164..b7fa1794e45 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java @@ -94,7 +94,7 @@ public class CatalogItemsPanel extends BasePanel implements IPageableItems { private IModel viewModel; private AssignmentViewType currentViewType = AssignmentViewType.ROLE_CATALOG_VIEW; - private long itemsPerRow = 3; + private long itemsPerRow = 4; private static final long DEFAULT_ROWS_COUNT = 5; private PageBase pageBase; private IModel viewTypeClassModel; 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 0027243b94d..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,16 +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: 15px; - padding-left: 10px; + padding-top: 10px; + padding-left: 12px; + padding-right: 12px; + padding-bottom: 10px; } } @@ -1109,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 From 6ea8ed325969f83d56966827df8414da990ebe96 Mon Sep 17 00:00:00 2001 From: honchar Date: Wed, 12 Oct 2016 14:56:54 +0200 Subject: [PATCH 13/15] role catalog session storage is created --- .../midpoint/gui/api/GuiStyleConstants.java | 3 + .../assignment/AssignmentCatalogPanel.java | 74 ++++++---- .../assignment/CatalogItemsPanel.java | 49 +++---- .../web/component/data/MultiButtonTable.java | 26 ++-- .../web/page/self/PageAssignmentDetails.java | 3 +- .../page/self/PageAssignmentShoppingKart.java | 31 ++-- .../web/page/self/PageAssignmentsList.java | 4 +- .../web/page/self/dto/AssignmentViewType.java | 13 ++ .../web/session/RoleCatalogStorage.java | 136 ++++++++++++++++++ .../midpoint/web/session/SessionStorage.java | 10 +- .../midpoint/web/session/UsersStorage.java | 10 -- 11 files changed, 253 insertions(+), 106 deletions(-) create mode 100644 gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RoleCatalogStorage.java 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 b6ed335a625..b1a0b4b716a 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,21 @@ 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.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,11 +49,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; - private IModel viewTypeClassModel; - private QName viewTypeClass; public AssignmentCatalogPanel(String id) { super(id); @@ -60,18 +65,22 @@ public AssignmentCatalogPanel(String id, String rootOid, PageBase pageBase) { super(id); this.pageBase = pageBase; this.rootOid = rootOid; - this.viewTypeClass = null; + AssignmentViewType.saveViewTypeToSession(pageBase, AssignmentViewType.ROLE_CATALOG_VIEW); initLayout(); } - public AssignmentCatalogPanel(String id, QName viewTypeClass, PageBase pageBase) { + public AssignmentCatalogPanel(String id, PageBase pageBase) { + this(id, AssignmentViewType.getViewTypeFromSession(pageBase), pageBase); + } + + public AssignmentCatalogPanel(String id, AssignmentViewType viewType, PageBase pageBase) { super(id); this.pageBase = pageBase; - this.viewTypeClass = viewTypeClass; - this.rootOid = null; + AssignmentViewType.saveViewTypeToSession(pageBase, viewType); initLayout(); } + private void initLayout() { initModels(); setOutputMarkupId(true); @@ -81,7 +90,7 @@ public void addOrReplaceLayout(){ WebMarkupContainer treePanelContainer = new WebMarkupContainer(ID_TREE_PANEL_CONTAINER); treePanelContainer.setOutputMarkupId(true); addOrReplace(treePanelContainer); - if (viewTypeClass == null) { + if (AssignmentViewType.ROLE_CATALOG_VIEW.equals(AssignmentViewType.getViewTypeFromSession(pageBase))) { OrgTreePanel treePanel = new OrgTreePanel(ID_TREE_PANEL, new IModel() { @Override public String getObject() { @@ -130,8 +139,8 @@ protected List createTreeChildrenMenu() { catalogItemsPanelContainer.setOutputMarkupId(true); addOrReplace(catalogItemsPanelContainer); - CatalogItemsPanel catalogItemsPanel = new CatalogItemsPanel(ID_CATALOG_ITEMS_PANEL, rootOidModel, viewTypeClassModel, pageBase); - if (viewTypeClass == null) { + 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 { catalogItemsPanelContainer.add(new AttributeAppender("class", "col-md-12")); @@ -143,8 +152,8 @@ protected List createTreeChildrenMenu() { private void selectTreeItemPerformed(SelectableBean selected, AjaxRequestTarget target) { final OrgType selectedOgr = selected.getValue(); rootOidModel.setObject(selectedOgr.getOid()); - viewTypeClassModel.setObject(null); - CatalogItemsPanel catalogItemsPanel = new CatalogItemsPanel(ID_CATALOG_ITEMS_PANEL, rootOidModel, viewTypeClassModel, pageBase); + 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); @@ -168,22 +177,27 @@ public void detach() { } }; - viewTypeClassModel = new IModel() { - @Override - public QName getObject() { - return viewTypeClass; - } - - @Override - public void setObject(QName qName) { - viewTypeClass = qName; - } - - @Override - public void detach() { + } - } - }; + 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.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java index b62b3445164..e212e226cb2 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java @@ -92,12 +92,10 @@ public class CatalogItemsPanel extends BasePanel implements IPageableItems { private ObjectDataProvider provider; private IModel> itemsListModel; private IModel viewModel; - private AssignmentViewType currentViewType = AssignmentViewType.ROLE_CATALOG_VIEW; private long itemsPerRow = 3; private static final long DEFAULT_ROWS_COUNT = 5; private PageBase pageBase; - private IModel viewTypeClassModel; private IModel catalogOidModel; private long currentPage = 0; @@ -105,16 +103,14 @@ public CatalogItemsPanel(String id) { super(id); } - public CatalogItemsPanel(String id, IModel catalogOidModel, IModel viewTypeClassModel, PageBase pageBase) { - this(id, catalogOidModel, viewTypeClassModel, pageBase, 0); + public CatalogItemsPanel(String id, IModel catalogOidModel, PageBase pageBase) { + this(id, catalogOidModel, pageBase, 0); } - public CatalogItemsPanel(String id, IModel catalogOidModel, IModel viewTypeClassModel, PageBase pageBase, int itemsPerRow) { + public CatalogItemsPanel(String id, IModel catalogOidModel, final PageBase pageBase, int itemsPerRow) { super(id); this.pageBase = pageBase; - this.viewTypeClassModel = viewTypeClassModel; this.catalogOidModel = catalogOidModel; - setCurrentViewType(viewTypeClassModel.getObject()); if (itemsPerRow > 0){ this.itemsPerRow = itemsPerRow; @@ -122,12 +118,12 @@ public CatalogItemsPanel(String id, IModel catalogOidModel, IModel() { @Override public AssignmentViewType getObject() { - return currentViewType; + return AssignmentViewType.getViewTypeFromSession(pageBase); } @Override public void setObject(AssignmentViewType assignmentViewType) { - currentViewType = assignmentViewType; + AssignmentViewType.saveViewTypeToSession(pageBase, assignmentViewType); } @Override @@ -226,7 +222,6 @@ private void initViewSelector(WebMarkupContainer headerPanel){ @Override protected void onUpdate(AjaxRequestTarget target) { - viewTypeClassModel.setObject(getViewTypeClass()); AssignmentCatalogPanel parentPanel = CatalogItemsPanel.this.findParent(AssignmentCatalogPanel.class); parentPanel.addOrReplaceLayout(); target.add(parentPanel); @@ -262,10 +257,10 @@ private void searchPerformed(ObjectQuery query, AjaxRequestTarget target) { protected ObjectQuery createContentQuery(ObjectQuery searchQuery) { ObjectQuery memberQuery; - if (viewTypeClassModel.getObject() == null){ + if (AssignmentViewType.ROLE_CATALOG_VIEW.equals(AssignmentViewType.getViewTypeFromSession(pageBase))){ memberQuery = createMemberQuery(catalogOidModel.getObject()); } else { - memberQuery = createMemberQuery(viewTypeClassModel.getObject()); + memberQuery = createMemberQuery(getViewTypeClass(AssignmentViewType.getViewTypeFromSession(pageBase))); } if (memberQuery == null) { memberQuery = new ObjectQuery(); @@ -340,16 +335,6 @@ protected WebMarkupContainer createFooter(String footerId) { return new PagingFooter(footerId, ID_PAGING_FOOTER, CatalogItemsPanel.this); } -// @Override -// public void setCurrentPage(ObjectPaging paging) { -//// WebComponentUtil.setCurrentPage(this, paging); -// } -// -// @Override -// public void setCurrentPage(long page) { -// getDataTable().setCurrentPage(page); -// } - private static class PagingFooter extends Fragment { public PagingFooter(String id, String markupId, CatalogItemsPanel markupProvider) { @@ -496,7 +481,7 @@ public void onClick(AjaxRequestTarget ajaxRequestTarget) { @Override public String getObject() { SessionStorage storage = pageBase.getSessionStorage(); - return Integer.toString(storage.getUsers().getAssignmentShoppingCart().size()); + return Integer.toString(storage.getRoleCatalog().getAssignmentShoppingCart().size()); } @Override @@ -514,7 +499,7 @@ public void detach() { @Override public boolean isVisible() { SessionStorage storage = pageBase.getSessionStorage(); - if (storage.getUsers().getAssignmentShoppingCart().size() == 0) { + if (storage.getRoleCatalog().getAssignmentShoppingCart().size() == 0) { return false; } else { return true; @@ -555,22 +540,22 @@ private PrismObject loadUser() { private void setCurrentViewType(QName viewTypeClass){ if (OrgType.COMPLEX_TYPE.equals(viewTypeClass)) { - currentViewType = AssignmentViewType.ORG_TYPE ; + AssignmentViewType.saveViewTypeToSession(pageBase, AssignmentViewType.ORG_TYPE) ; } else if (RoleType.COMPLEX_TYPE.equals(viewTypeClass)) { - currentViewType = AssignmentViewType.ROLE_TYPE ; + AssignmentViewType.saveViewTypeToSession(pageBase, AssignmentViewType.ROLE_TYPE) ; } else if (ServiceType.COMPLEX_TYPE.equals(viewTypeClass)) { - currentViewType = AssignmentViewType.SERVICE_TYPE ; + AssignmentViewType.saveViewTypeToSession(pageBase, AssignmentViewType.SERVICE_TYPE) ; } else { - currentViewType = AssignmentViewType.ROLE_CATALOG_VIEW ; + AssignmentViewType.saveViewTypeToSession(pageBase, AssignmentViewType.ROLE_CATALOG_VIEW) ; } } - private QName getViewTypeClass() { - if (AssignmentViewType.ORG_TYPE.equals(currentViewType)) { + private QName getViewTypeClass(AssignmentViewType viewType) { + if (AssignmentViewType.ORG_TYPE.equals(viewType)) { return OrgType.COMPLEX_TYPE; - } else if (AssignmentViewType.ROLE_TYPE.equals(currentViewType)) { + } else if (AssignmentViewType.ROLE_TYPE.equals(viewType)) { return RoleType.COMPLEX_TYPE; - } else if (AssignmentViewType.SERVICE_TYPE.equals(currentViewType)) { + } else if (AssignmentViewType.SERVICE_TYPE.equals(viewType)) { return ServiceType.COMPLEX_TYPE; } return null; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java index 9bf6cd11e15..ac77188e834 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/MultiButtonTable.java @@ -15,12 +15,14 @@ */ package com.evolveum.midpoint.web.component.data; +import com.evolveum.midpoint.gui.api.GuiStyleConstants; 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.web.component.AjaxIconButton; import com.evolveum.midpoint.web.component.assignment.*; import com.evolveum.midpoint.web.page.self.PageAssignmentDetails; +import com.evolveum.midpoint.web.session.RoleCatalogStorage; import com.evolveum.midpoint.web.session.UsersStorage; import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxEventBehavior; @@ -155,16 +157,6 @@ public void onClick(AjaxRequestTarget ajaxRequestTarget) { }; cellContainer.add(addToCartLink); -// Label addToCartLinkLabel = new Label(ID_ADD_TO_CART_LINK_LABEL, pageBase.createStringResource("MultiButtonPanel.addToCartLink")); -// addToCartLinkLabel.setRenderBodyOnly(true); -// addToCartLinkLabel.add(new AjaxEventBehavior("click") { -// @Override -// protected void onEvent(AjaxRequestTarget ajaxRequestTarget) { -// addAssignmentPerformed(assignment, ajaxRequestTarget); -// } -// }); -// addToCartLink.add(addToCartLinkLabel); - AjaxLink addToCartLinkIcon = new AjaxLink(ID_ADD_TO_CART_LINK_ICON) { private static final long serialVersionUID = 1L; @@ -210,11 +202,11 @@ public void detach() { private String getIconClass(AssignmentEditorDtoType type){ // TODO: switch to icon constants if (AssignmentEditorDtoType.ROLE.equals(type)){ - return "fa fa-street-view"; + return GuiStyleConstants.CLASS_OBJECT_ROLE_ICON; }else if (AssignmentEditorDtoType.SERVICE.equals(type)){ - return "fa fa-cloud"; + return GuiStyleConstants.CLASS_OBJECT_SERVICE_ICON; }else if (AssignmentEditorDtoType.ORG_UNIT.equals(type)){ - return "fa fa-building"; + return GuiStyleConstants.CLASS_OBJECT_ORG_ICON; } else { return ""; } @@ -222,11 +214,11 @@ private String getIconClass(AssignmentEditorDtoType type){ private String getBackgroundClass(AssignmentEditorDtoType type){ if (AssignmentEditorDtoType.ROLE.equals(type)){ - return "object-role-bg"; + return GuiStyleConstants.CLASS_OBJECT_ROLE_BG; }else if (AssignmentEditorDtoType.SERVICE.equals(type)){ - return "object-service-bg"; + return GuiStyleConstants.CLASS_OBJECT_SERVICE_BG; }else if (AssignmentEditorDtoType.ORG_UNIT.equals(type)){ - return "object-org-bg"; + return GuiStyleConstants.CLASS_OBJECT_ORG_BG; } else { return ""; } @@ -234,7 +226,7 @@ private String getBackgroundClass(AssignmentEditorDtoType type){ private void addAssignmentPerformed(AssignmentEditorDto assignment, AjaxRequestTarget target){ plusIconClicked = true; - UsersStorage storage = getPageBase().getSessionStorage().getUsers(); + RoleCatalogStorage storage = getPageBase().getSessionStorage().getRoleCatalog(); if (storage.getAssignmentShoppingCart() == null){ storage.setAssignmentShoppingCart(new ArrayList()); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentDetails.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentDetails.java index 1baf101fa0a..295d3dffb11 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentDetails.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageAssignmentDetails.java @@ -10,6 +10,7 @@ import com.evolveum.midpoint.web.component.assignment.AssignmentEditorDto; import com.evolveum.midpoint.web.component.form.Form; import com.evolveum.midpoint.web.page.admin.roles.PageAdminRoles; +import com.evolveum.midpoint.web.session.RoleCatalogStorage; import com.evolveum.midpoint.web.session.UsersStorage; import com.evolveum.midpoint.web.util.OnePageParameterEncoder; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -69,7 +70,7 @@ public void onClick(AjaxRequestTarget target) { @Override public void onClick(AjaxRequestTarget target) { - UsersStorage storage = getSessionStorage().getUsers(); + RoleCatalogStorage storage = getSessionStorage().getRoleCatalog(); if (storage.getAssignmentShoppingCart() == null){ storage.setAssignmentShoppingCart(new ArrayList()); } 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 6cb9c87851c..c32ff862c17 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,8 +57,8 @@ 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 DOT_CLASS = PageAssignmentShoppingKart.class.getName() + "."; @@ -67,7 +67,6 @@ public class PageAssignmentShoppingKart extends PageSelf { private String catalogOid = null; private boolean isFirstInit = true; - private QName currentViewClass; public PageAssignmentShoppingKart() { initLayout(); @@ -106,21 +105,27 @@ private String getRoleCatalogOid() { return ""; } - private Component initMainPanel(){ - if (StringUtils.isEmpty(catalogOid)) { - if (isFirstInit){ - isFirstInit = false; - currentViewClass = RoleType.COMPLEX_TYPE; - AssignmentCatalogPanel panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, currentViewClass, PageAssignmentShoppingKart.this); - panel.setOutputMarkupId(true); - return panel; + 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 { + Label panel = new Label(ID_MAIN_PANEL, createStringResource("PageAssignmentShoppingKart.roleCatalogIsNotConfigured")); + panel.setOutputMarkupId(true); + return panel; + } } else { - Label panel = new Label(ID_MAIN_PANEL, createStringResource("PageAssignmentShoppingKart.roleCatalogIsNotConfigured")); + AssignmentCatalogPanel panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, catalogOid, PageAssignmentShoppingKart.this); 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.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); From d27fec89ffdeefa392cb72695185c768e95815d4 Mon Sep 17 00:00:00 2001 From: honchar Date: Wed, 12 Oct 2016 16:22:36 +0200 Subject: [PATCH 14/15] role catalog fixes --- .../assignment/AssignmentCatalogPanel.java | 13 +++- .../assignment/CatalogItemsPanel.java | 59 +++++++++++++------ .../page/self/PageAssignmentShoppingKart.java | 1 + 3 files changed, 53 insertions(+), 20 deletions(-) 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 b1a0b4b716a..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 @@ -29,9 +29,11 @@ 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.model.IModel; import javax.xml.namespace.QName; @@ -65,7 +67,6 @@ public AssignmentCatalogPanel(String id, String rootOid, PageBase pageBase) { super(id); this.pageBase = pageBase; this.rootOid = rootOid; - AssignmentViewType.saveViewTypeToSession(pageBase, AssignmentViewType.ROLE_CATALOG_VIEW); initLayout(); } @@ -90,7 +91,7 @@ public void addOrReplaceLayout(){ WebMarkupContainer treePanelContainer = new WebMarkupContainer(ID_TREE_PANEL_CONTAINER); treePanelContainer.setOutputMarkupId(true); addOrReplace(treePanelContainer); - if (AssignmentViewType.ROLE_CATALOG_VIEW.equals(AssignmentViewType.getViewTypeFromSession(pageBase))) { + 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() { @@ -179,6 +180,14 @@ 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(); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java index c40424b8d1b..967f5f85dab 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/CatalogItemsPanel.java @@ -41,6 +41,7 @@ import com.evolveum.midpoint.web.security.SecurityUtils; 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.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.OnChangeAjaxBehavior; @@ -148,7 +149,13 @@ private void initLayout() { initCartButton(headerPanel); initSearchPanel(headerPanel); - MultiButtonTable assignmentsTable = new MultiButtonTable(ID_MULTI_BUTTON_TABLE, itemsPerRow, itemsListModel, pageBase); + Component assignmentsTable; + if ((catalogOidModel == null || StringUtils.isEmpty(catalogOidModel.getObject())) && + AssignmentViewType.ROLE_CATALOG_VIEW.equals(AssignmentViewType.getViewTypeFromSession(pageBase))) { + assignmentsTable = new Label(ID_MULTI_BUTTON_TABLE, createStringResource("PageAssignmentShoppingKart.roleCatalogIsNotConfigured")); + } else { + assignmentsTable = new MultiButtonTable(ID_MULTI_BUTTON_TABLE, itemsPerRow, itemsListModel, pageBase); + } assignmentsTable.setOutputMarkupId(true); add(assignmentsTable); @@ -157,28 +164,32 @@ private void initLayout() { } protected void initProvider() { + if ((catalogOidModel == null || StringUtils.isEmpty(catalogOidModel.getObject())) + && AssignmentViewType.ROLE_CATALOG_VIEW.equals(AssignmentViewType.getViewTypeFromSession(pageBase))){ + provider = null; + } else { + provider = new ObjectDataProvider(pageBase, AbstractRoleType.class) { + private static final long serialVersionUID = 1L; - provider = new ObjectDataProvider(pageBase, AbstractRoleType.class) { - private static final long serialVersionUID = 1L; - - @Override - public AssignmentEditorDto createDataObjectWrapper(PrismObject obj) { - return AssignmentEditorDto.createDtoFromObject(obj.asObjectable(), UserDtoStatus.MODIFY, pageBase); - } + @Override + public AssignmentEditorDto createDataObjectWrapper(PrismObject obj) { + return AssignmentEditorDto.createDtoFromObject(obj.asObjectable(), UserDtoStatus.MODIFY, pageBase); + } - @Override - public void setQuery(ObjectQuery query) { + @Override + public void setQuery(ObjectQuery query) { - super.setQuery(query); - } + super.setQuery(query); + } - @Override - public ObjectQuery getQuery() { + @Override + public ObjectQuery getQuery() { - return createContentQuery(null); - } - }; - setCurrentPage(0); + return createContentQuery(null); + } + }; + setCurrentPage(0); + } } protected void refreshCatalogItemsPanel() { @@ -235,6 +246,12 @@ protected void onUpdate(AjaxRequestTarget target) { private void initSearchPanel(WebMarkupContainer headerPanel) { final Form searchForm = new Form(ID_SEARCH_FORM); headerPanel.add(searchForm); + searchForm.add(new VisibleEnableBehaviour(){ + public boolean isVisible(){ + return !(AssignmentViewType.ROLE_CATALOG_VIEW.equals(AssignmentViewType.getViewTypeFromSession(pageBase)) && + (catalogOidModel != null || StringUtils.isNotEmpty(catalogOidModel.getObject()))); + } + }); searchForm.setOutputMarkupId(true); SearchPanel search = new SearchPanel(ID_SEARCH, (IModel) searchModel, false) { @@ -474,6 +491,12 @@ public void onClick(AjaxRequestTarget ajaxRequestTarget) { setResponsePage(new PageAssignmentsList(loadUser())); } }; + cartButton.add(new VisibleEnableBehaviour(){ + public boolean isVisible(){ + return !(AssignmentViewType.ROLE_CATALOG_VIEW.equals(AssignmentViewType.getViewTypeFromSession(pageBase)) && + (catalogOidModel != null || StringUtils.isNotEmpty(catalogOidModel.getObject()))); + } + }); cartButton.setOutputMarkupId(true); headerPanel.add(cartButton); 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 c32ff862c17..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 @@ -126,6 +126,7 @@ private Component initMainPanel() { } } else { AssignmentCatalogPanel panel = new AssignmentCatalogPanel(ID_MAIN_PANEL, PageAssignmentShoppingKart.this); + panel.setRootOid(catalogOid); panel.setOutputMarkupId(true); return panel; } From f486b2b7a1e89bbe763aa86a1daffe51fa333b64 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 12 Oct 2016 18:17:27 +0200 Subject: [PATCH 15/15] Object merge, step 3: expressions (MID-3460) --- .../evolveum/midpoint/prism/PrismValue.java | 12 ++ .../schema/constants/ExpressionConstants.java | 5 + .../xml/ns/public/common/common-core-3.xsd | 38 +++- .../model/api/ModelInteractionService.java | 4 +- .../ModelInteractionServiceImpl.java | 8 +- .../model/impl/controller/ObjectMerger.java | 184 ++++++++++++++---- .../midpoint/model/intest/TestMerge.java | 121 +++++++++++- .../resources/common/system-configuration.xml | 75 ++++++- 8 files changed, 397 insertions(+), 50 deletions(-) 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/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/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index 49a7bef79a0..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 @@ -12544,8 +12544,29 @@ - - + + + + 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. + + + @@ -12577,6 +12598,7 @@ + Ignore all the values. @@ -12586,12 +12608,24 @@ + Take all the values. + + + + Take only values that are selected and processed by the expression. + + + + + + + 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 bf4655d17a3..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 @@ -184,10 +184,10 @@ ConnectorOperationalStatus getConnectorOperationalStatus(String resourceOid, Ope ObjectDelta mergeObjectsPreviewDelta(Class type, String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult result) - throws ObjectNotFoundException, SchemaException, ConfigurationException; + throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException; PrismObject mergeObjectsPreviewObject(Class type, String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult result) - throws ObjectNotFoundException, SchemaException, ConfigurationException; + throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException; } 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 d1e924ea9ed..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 @@ -709,7 +709,7 @@ public ConnectorOperationalStatus getConnectorOperationalStatus(String resourceO @Override public ObjectDelta mergeObjectsPreviewDelta(Class type, String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, ConfigurationException { + throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException { OperationResult result = parentResult.createMinorSubresult(MERGE_OBJECTS_PREVIEW_DELTA); try { @@ -719,7 +719,7 @@ public ObjectDelta mergeObjectsPreviewDelta(Class t result.computeStatus(); return objectDelta; - } catch (ObjectNotFoundException | SchemaException | ConfigurationException | RuntimeException | Error e) { + } catch (ObjectNotFoundException | SchemaException | ConfigurationException | ExpressionEvaluationException | RuntimeException | Error e) { result.recordFatalError(e); throw e; } @@ -728,7 +728,7 @@ public ObjectDelta mergeObjectsPreviewDelta(Class t @Override public PrismObject mergeObjectsPreviewObject(Class type, String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, ConfigurationException { + throws ObjectNotFoundException, SchemaException, ConfigurationException, ExpressionEvaluationException { OperationResult result = parentResult.createMinorSubresult(MERGE_OBJECTS_PREVIEW_OBJECT); try { @@ -747,7 +747,7 @@ public PrismObject mergeObjectsPreviewObject(Class result.computeStatus(); return objectLeft; - } catch (ObjectNotFoundException | SchemaException | ConfigurationException | RuntimeException | Error e) { + } 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 index ad80f036362..b9bb70d8d32 100644 --- 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 @@ -25,6 +25,10 @@ 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; @@ -37,9 +41,11 @@ 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; @@ -54,6 +60,7 @@ 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; @@ -72,12 +79,18 @@ 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; @@ -115,8 +128,8 @@ public Collection ObjectDelta computeMergeDelta(Class type, String leftOid, String rightOid, - String mergeConfigurationName, Task task, OperationResult result) - throws ObjectNotFoundException, SchemaException, ConfigurationException { + 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(); @@ -134,7 +147,7 @@ public ObjectDelta computeMergeDelta(Class type, St for (ItemRefMergeConfigurationType itemMergeConfig: mergeConfiguration.getItem()) { ItemPath itemPath = itemMergeConfig.getRef().getItemPath(); processedPaths.add(itemPath); - ItemDelta itemDelta = mergeItem(objectLeft, objectRight, itemMergeConfig, 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); @@ -188,8 +201,9 @@ public void visit(Visitable visitable) { ItemDelta itemDelta; try { - itemDelta = mergeItem(objectLeft, objectRight, defaultItemMergeConfig, itemPath); - } catch (SchemaException e) { + 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); @@ -206,6 +220,12 @@ public void visit(Visitable visitable) { } 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); } @@ -217,7 +237,8 @@ public void visit(Visitable visitable) { } private ItemDelta mergeItem(PrismObject objectLeft, PrismObject objectRight, - ItemMergeConfigurationType itemMergeConfig, ItemPath itemPath) throws SchemaException { + 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) { @@ -234,6 +255,15 @@ private ItemDelta mergeItem(PrismObject 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(); @@ -247,52 +277,140 @@ private ItemDelta mergeItem(PrismObject valuesToTake = getValuesToTake(objectLeft, objectRight, + SIDE_RIGHT, itemRight, rightStrategy, valueExpression, task, result); + itemDelta.setValuesToReplace(valuesToTake); } return itemDelta; } } else { if (rightStrategy == null || rightStrategy == MergeStategyType.IGNORE) { - // TAKE left, IGNORE right - return null; - } else { - // TAKE left, TAKE right - if (itemDefinition.isSingleValue()) { - if (itemLeft == null) { - itemDelta.setValuesToReplace(itemRight.getClonedValues()); + 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 if (itemRight != null) { - throw new SchemaException("Attempt to put multiple values in a single-valued item "+itemPath); } 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 { - if (itemLeft == null) { - itemDelta.addValuesToAdd(itemRight.getClonedValues()); - return itemDelta; - } else { - // We want to add only those values that are not yet there. - // E.g. adding assignments that are there can cause unneccesary churn - List valuesRight = itemRight.getValues(); - for (PrismValue valueRight: valuesRight) { - if (!itemLeft.containsEquivalentValue(valueRight)) { - PrismValue clonedValue = valueRight.clone(); - if (clonedValue instanceof PrismContainerValue) { - ((PrismContainerValue)clonedValue).setId(null); - } - itemDelta.addValueToAdd(clonedValue); - } + // 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); } - return itemDelta; } + + 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 { 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 index 7828aaf2b4e..ca192dca2c4 100644 --- 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 @@ -47,6 +47,7 @@ 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 { @@ -55,13 +56,13 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti 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("Scurvy Seadogs")); + 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("Scurvy Seadogs")); + 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); @@ -111,7 +112,7 @@ public void test100MergeJackGuybrushPreviewDelta() throws Exception { PrismAsserts.assertPropertyAdd(delta, UserType.F_EMPLOYEE_TYPE, "SAILOR", "PIRATE WANNABE"); PrismAsserts.assertPropertyAdd(delta, UserType.F_ORGANIZATION, - createPolyString("Pirate Wannabes")); + createPolyString("Pirate Wannabes"), createPolyString("Lovers")); PrismAsserts.assertNoItemDelta(delta, UserType.F_ACTIVATION); PrismAsserts.assertNoItemDelta(delta, new ItemPath(UserType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS)); @@ -161,7 +162,8 @@ public void test102MergeJackGuybrushPreviewObject() throws Exception { UserType.F_EMPLOYEE_TYPE, USER_JACK_EMPLOYEE_TYPE, "SAILOR", "PIRATE WANNABE"); PrismAsserts.assertPropertyValue(object, UserType.F_ORGANIZATION, - createPolyString("Pirate Brethren"), createPolyString("Scurvy Seadogs"), createPolyString("Pirate Wannabes")); + 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); @@ -211,7 +213,7 @@ public void test110MergeGuybrushJackPreviewDelta() throws Exception { PrismAsserts.assertPropertyAdd(delta, UserType.F_EMPLOYEE_TYPE, USER_JACK_EMPLOYEE_TYPE); PrismAsserts.assertPropertyAdd(delta, UserType.F_ORGANIZATION, - createPolyString("Pirate Brethren")); + createPolyString("Pirate Brethren"), createPolyString("Drinkers")); PrismAsserts.assertNoItemDelta(delta, UserType.F_ACTIVATION); PrismAsserts.assertNoItemDelta(delta, new ItemPath(UserType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS)); @@ -264,19 +266,122 @@ public void test112MergeGuybrushJackPreviewObject() throws Exception { UserType.F_EMPLOYEE_TYPE, USER_JACK_EMPLOYEE_TYPE, "SAILOR", "PIRATE WANNABE"); PrismAsserts.assertPropertyValue(object, UserType.F_ORGANIZATION, - createPolyString("Pirate Brethren"), createPolyString("Scurvy Seadogs"), createPolyString("Pirate Wannabes")); + 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 test200MergeJackGuybrush() throws Exception { - final String TEST_NAME = "test200MergeJackGuybrush"; + public void test500MergeJackGuybrush() throws Exception { + final String TEST_NAME = "test500MergeJackGuybrush"; TestUtil.displayTestTile(this, TEST_NAME); Task task = taskManager.createTaskInstance(TestMerge.class.getName() + "." + TEST_NAME); 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 979c886a42f..4d93bcc4508 100644 --- a/model/model-intest/src/test/resources/common/system-configuration.xml +++ b/model/model-intest/src/test/resources/common/system-configuration.xml @@ -226,7 +226,7 @@ take take - + linkRef take @@ -252,4 +252,77 @@ 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 + + +