From fe73573cdb4c642cb4021cbe34caf6c3709f0635 Mon Sep 17 00:00:00 2001 From: Erik Suta Date: Mon, 21 Jul 2014 12:46:14 +0200 Subject: [PATCH 01/51] Reworked search on modal window in ChangeOwner dialog. --- .../component/dialog/UserBrowserDialog.html | 54 ++++++------ .../component/dialog/UserBrowserDialog.java | 88 ++++++++++++------- .../web/component/dialog/UserBrowserDto.java | 6 ++ 3 files changed, 92 insertions(+), 56 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDialog.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDialog.html index b2e4f252c75..ce1f551e1c4 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDialog.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDialog.html @@ -16,33 +16,35 @@
-
-
- - - - - - - - - - -
- - - - -
- - - - - -
- -
+ + + + + + + + + + +
+ + + + +
+ + + + + +
+ +
+ + +

diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDialog.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDialog.java index b6a4911fdbc..aca2ab9d3f0 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDialog.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDialog.java @@ -27,7 +27,7 @@ import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.AjaxButton; -import com.evolveum.midpoint.web.component.AjaxSubmitButton; +import com.evolveum.midpoint.web.component.BasicSearchPanel; import com.evolveum.midpoint.web.component.data.ObjectDataProvider; import com.evolveum.midpoint.web.component.data.TablePanel; import com.evolveum.midpoint.web.component.data.column.IconColumn; @@ -50,7 +50,6 @@ import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.Form; -import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.*; @@ -62,6 +61,16 @@ */ public class UserBrowserDialog extends ModalWindow { + private static final String ID_SEARCH_FORM = "searchForm"; + private static final String ID_MAIN_FORM = "mainForm"; + private static final String ID_CHECK_NAME = "nameCheck"; + private static final String ID_CHECK_FULL_NAME = "fullNameCheck"; + private static final String ID_CHECK_GIVEN_NAME = "givenNameCheck"; + private static final String ID_CHECK_FAMILY_NAME = "familyNameCheck"; + private static final String ID_BASIC_SEARCH = "basicSearch"; + private static final String ID_BUTTON_CANCEL = "cancelButton"; + private static final String ID_TABLE = "table"; + private static final Trace LOGGER = TraceManager.getTrace(UserBrowserDialog.class); private IModel model; private boolean initialized; @@ -102,44 +111,51 @@ protected void onBeforeRender() { } private void initLayout(WebMarkupContainer content) { - Form mainForm = new Form("mainForm"); + Form mainForm = new Form(ID_MAIN_FORM); content.add(mainForm); - TextField search = new TextField("searchText", new PropertyModel(model, "searchText")); - mainForm.add(search); + Form searchForm = new Form(ID_SEARCH_FORM); + searchForm.setOutputMarkupId(true); + content.add(searchForm); - CheckBox nameCheck = new CheckBox("nameCheck", new PropertyModel(model, "name")); - mainForm.add(nameCheck); - CheckBox fullNameCheck = new CheckBox("fullNameCheck", new PropertyModel(model, "fullName")); - mainForm.add(fullNameCheck); - CheckBox givenNameCheck = new CheckBox("givenNameCheck", new PropertyModel(model, "givenName")); - mainForm.add(givenNameCheck); - CheckBox familyNameCheck = new CheckBox("familyNameCheck", new PropertyModel(model, "familyName")); - mainForm.add(familyNameCheck); +// TextField search = new TextField("searchText", new PropertyModel(model, "searchText")); +// mainForm.add(search); + CheckBox nameCheck = new CheckBox(ID_CHECK_NAME, new PropertyModel(model, UserBrowserDto.F_NAME)); + searchForm.add(nameCheck); + CheckBox fullNameCheck = new CheckBox(ID_CHECK_FULL_NAME, new PropertyModel(model, UserBrowserDto.F_FULL_NAME)); + searchForm.add(fullNameCheck); + CheckBox givenNameCheck = new CheckBox(ID_CHECK_GIVEN_NAME, new PropertyModel(model, UserBrowserDto.F_GIVEN_NAME)); + searchForm.add(givenNameCheck); + CheckBox familyNameCheck = new CheckBox(ID_CHECK_FAMILY_NAME, new PropertyModel(model, UserBrowserDto.F_FAMILY_NAME)); + searchForm.add(familyNameCheck); - List, String>> columns = initColumns(); - TablePanel table = new TablePanel>("table", - new ObjectDataProvider(getPageBase(), UserType.class), columns); - table.setOutputMarkupId(true); - mainForm.add(table); + BasicSearchPanel basicSearch = new BasicSearchPanel(ID_BASIC_SEARCH) { - AjaxSubmitButton searchButton = new AjaxSubmitButton("searchButton", - createStringResource("userBrowserDialog.button.searchButton")) { + @Override + protected IModel createSearchTextModel() { + return new PropertyModel<>(model, UserBrowserDto.F_SEARCH_TEXT); + } @Override - protected void onError(AjaxRequestTarget target, Form form) { - target.add(getPageBase().getFeedbackPanel()); + protected void searchPerformed(AjaxRequestTarget target) { + UserBrowserDialog.this.searchPerformed(target); } @Override - protected void onSubmit(AjaxRequestTarget target, Form form) { - searchPerformed(target); + protected void clearSearchPerformed(AjaxRequestTarget target) { + UserBrowserDialog.this.clearSearchPerformed(target); } }; - mainForm.add(searchButton); + searchForm.add(basicSearch); + + List, String>> columns = initColumns(); + TablePanel table = new TablePanel<>(ID_TABLE, + new ObjectDataProvider(getPageBase(), UserType.class), columns); + table.setOutputMarkupId(true); + mainForm.add(table); - AjaxButton cancelButton = new AjaxButton("cancelButton", + AjaxButton cancelButton = new AjaxButton(ID_BUTTON_CANCEL, createStringResource("userBrowserDialog.button.cancelButton")) { @Override @@ -176,7 +192,7 @@ public String getObject() { } }); - IColumn column = new LinkColumn>(createStringResource("userBrowserDialog.name"), "name", "value.name") { + IColumn column = new LinkColumn>(createStringResource("userBrowserDialog.name"), UserBrowserDto.F_NAME, "value.name") { @Override public void onClick(AjaxRequestTarget target, IModel> rowModel) { @@ -186,13 +202,13 @@ public void onClick(AjaxRequestTarget target, IModel> r }; columns.add(column); - column = new PropertyColumn(createStringResource("userBrowserDialog.givenName"), "givenName", "value.givenName"); + column = new PropertyColumn(createStringResource("userBrowserDialog.givenName"), UserBrowserDto.F_GIVEN_NAME, SelectableBean.F_VALUE + ".givenName"); columns.add(column); - column = new PropertyColumn(createStringResource("userBrowserDialog.familyName"), "familyName", "value.familyName"); + column = new PropertyColumn(createStringResource("userBrowserDialog.familyName"), UserBrowserDto.F_FAMILY_NAME, SelectableBean.F_VALUE + ".familyName"); columns.add(column); - column = new PropertyColumn(createStringResource("userBrowserDialog.fullName"), "fullName", "value.fullName.orig"); + column = new PropertyColumn(createStringResource("userBrowserDialog.fullName"), UserBrowserDto.F_FULL_NAME, SelectableBean.F_VALUE + ".fullName.orig"); columns.add(column); column = new AbstractColumn, String>(createStringResource("userBrowserDialog.email")) { @@ -275,6 +291,18 @@ private ObjectQuery createQuery() { return query; } + private void clearSearchPerformed(AjaxRequestTarget target){ + model.setObject(new UserBrowserDto()); + + TablePanel panel = getTable(); + DataTable table = panel.getDataTable(); + ObjectDataProvider provider = (ObjectDataProvider) table.getDataProvider(); + provider.setQuery(null); + + target.add(getContent().get(ID_SEARCH_FORM)); + target.add(panel); + } + private void cancelPerformed(AjaxRequestTarget target) { close(target); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDto.java index 0f7a256553c..8295cd5337e 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/UserBrowserDto.java @@ -23,6 +23,12 @@ */ public class UserBrowserDto implements Serializable { + public static final String F_SEARCH_TEXT = "searchText"; + public static final String F_NAME = "name"; + public static final String F_FULL_NAME = "fullName"; + public static final String F_GIVEN_NAME = "givenName"; + public static final String F_FAMILY_NAME = "familyName"; + private String searchText; private boolean name = true; private boolean fullName; From 9738ced6c9c19a39d27369e96a2d5f54b92ea778 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Mon, 21 Jul 2014 14:09:56 +0200 Subject: [PATCH 02/51] cxf-xjc-runtime depdendncy --- infra/ws-util/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/infra/ws-util/pom.xml b/infra/ws-util/pom.xml index 872ee076cfc..a05f74442b3 100644 --- a/infra/ws-util/pom.xml +++ b/infra/ws-util/pom.xml @@ -77,6 +77,12 @@ org.apache.cxf cxf-rt-frontend-simple + + + org.apache.cxf.xjc-utils + cxf-xjc-runtime + org.testng From 596ff219b5484c78c594a015b8c59bd85d1efbfa Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Mon, 21 Jul 2014 16:44:21 +0200 Subject: [PATCH 03/51] fixing MID-1976 (dennyAll-like action for development pages) --- .../web/application/DescriptorLoader.java | 19 ++++++++++++++++++- .../evolveum/midpoint/web/page/PageTest.java | 2 +- .../evolveum/midpoint/web/page/PageTest2.java | 2 +- .../admin/configuration/PageBulkAction.java | 2 +- .../admin/resources/PageResourceWizard.java | 2 +- .../content/PageContentEntitlements.java | 2 +- .../web/page/admin/users/PageFindUsers.java | 2 +- .../midpoint/web/page/login/PageLogin.java | 3 +++ .../MidPointGuiAuthorizationEvaluator.java | 2 +- .../main/webapp/WEB-INF/ctx-web-security.xml | 5 +++-- .../security/api/AuthorizationConstants.java | 4 ++-- .../security/impl/SecurityEnforcerImpl.java | 6 ++++++ 12 files changed, 39 insertions(+), 12 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/application/DescriptorLoader.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/application/DescriptorLoader.java index 46349bef831..72eeca108d2 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/application/DescriptorLoader.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/application/DescriptorLoader.java @@ -185,11 +185,28 @@ private void scanPackagesForPages(List packages, MidPointApplication app private void loadActions(PageDescriptor descriptor) { for (String url : descriptor.url()) { List actions = new ArrayList<>(); + + //avoid of setting guiAll authz for "public" pages (e.g. login page) + if (descriptor.action() == null || descriptor.action().length == 0){ + return; + } + + boolean canAccess = true; + for (AuthorizationAction action : descriptor.action()) { actions.add(new AuthorizationActionValue(action.actionUri(), action.label(), action.description())); + if (AuthorizationConstants.AUTZ_NO_ACCESS_URL.equals(action.actionUri())){ + canAccess = false; + break; + } } - actions.add(new AuthorizationActionValue(AuthorizationConstants.AUTZ_GUI_ALL_URI, + + //add http://.../..#guAll authorization only for displayable pages, not for pages used for development.. + if (canAccess){ + + actions.add(new AuthorizationActionValue(AuthorizationConstants.AUTZ_GUI_ALL_URI, AuthorizationConstants.AUTZ_GUI_ALL_LABEL, AuthorizationConstants.AUTZ_GUI_ALL_DESCRIPTION)); + } this.actions.put(url, actions.toArray(new DisplayableValue[actions.size()])); } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/PageTest.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/PageTest.java index cc0e429e592..6bfced82ed7 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/PageTest.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/PageTest.java @@ -31,7 +31,7 @@ /** * @author lazyman */ -@PageDescriptor(url = "/admin/test", action = {@AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_DEVEL_URL)}) +@PageDescriptor(url = "/admin/test", action = {@AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_NO_ACCESS_URL)}) public class PageTest extends PageBase { public PageTest() { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/PageTest2.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/PageTest2.java index 001b17a520d..ab06869a7a7 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/PageTest2.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/PageTest2.java @@ -33,7 +33,7 @@ * * @author shood */ -@PageDescriptor(url = "/capability", action = {@AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_DEVEL_URL)}) +@PageDescriptor(url = "/capability", action = {@AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_NO_ACCESS_URL)}) public class PageTest2 extends PageBase { private static final String ID_CAPABILITY = "capability"; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java index 29009292c83..cc0f6c18588 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java @@ -37,7 +37,7 @@ // label = PageAdminConfiguration.AUTH_CONFIGURATION_ALL_LABEL, description = PageAdminConfiguration.AUTH_CONFIGURATION_ALL_DESCRIPTION), // @AuthorizationAction(actionUri = AuthorizationConstants.NS_AUTHORIZATION + "#bulkAction", // label = "PageBulkAction.auth.bulkAction.label", description = "PageBulkAction.auth.bulkAction.description") - @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_DEVEL_URL) + @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_NO_ACCESS_URL) }) public class PageBulkAction extends PageAdminConfiguration { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResourceWizard.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResourceWizard.java index 3d687977d41..e919d7da8dd 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResourceWizard.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResourceWizard.java @@ -44,7 +44,7 @@ // PageAdminResources.AUTHORIZATION_RESOURCE_ALL, // AuthorizationConstants.NS_AUTHORIZATION + "#resourceWizard"}) @PageDescriptor(url = "/admin/resources/wizard", - action = {@AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_DEVEL_URL)}) + action = {@AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_NO_ACCESS_URL)}) public class PageResourceWizard extends PageAdminResources { private static final String ID_WIZARD = "wizard"; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageContentEntitlements.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageContentEntitlements.java index 41ac3fdd714..24c4af07f82 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageContentEntitlements.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageContentEntitlements.java @@ -35,7 +35,7 @@ * @author lazyman */ @PageDescriptor(url = "/admin/resources/content/entitlements", encoder = OnePageParameterEncoder.class, action = { - @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_DEVEL_URL)}) + @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_NO_ACCESS_URL)}) public class PageContentEntitlements extends PageAdminResources { private IModel> resourceModel; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageFindUsers.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageFindUsers.java index 763508c785e..124a2a63be8 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageFindUsers.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageFindUsers.java @@ -25,7 +25,7 @@ /** * @author lazyman */ -@PageDescriptor(url = "/admin/users/find", action = {@AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_DEVEL_URL)}) +@PageDescriptor(url = "/admin/users/find", action = {@AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_NO_ACCESS_URL)}) public class PageFindUsers extends PageAdminUsers { private static final Trace LOGGER = TraceManager.getTrace(PageFindUsers.class); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageLogin.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageLogin.java index 4b2327a88fd..65b5552493a 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageLogin.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageLogin.java @@ -16,12 +16,15 @@ package com.evolveum.midpoint.web.page.login; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.web.application.AuthorizationAction; import com.evolveum.midpoint.web.application.PageDescriptor; import com.evolveum.midpoint.web.component.menu.top.LocalePanel; import com.evolveum.midpoint.web.component.menu.top.TopMenuBar; import com.evolveum.midpoint.web.page.PageBase; import com.evolveum.midpoint.web.page.admin.home.PageDashboard; import com.evolveum.midpoint.web.security.MidPointAuthWebSession; + import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.PasswordTextField; import org.apache.wicket.markup.html.form.RequiredTextField; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointGuiAuthorizationEvaluator.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointGuiAuthorizationEvaluator.java index a52fbfbe548..8485b3fe6a0 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointGuiAuthorizationEvaluator.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointGuiAuthorizationEvaluator.java @@ -118,7 +118,7 @@ public void decide(Authentication authentication, Object object, Collection - + + @@ -54,7 +55,7 @@ http://www.springframework.org/schema/security/spring-security-3.1.xsd"> - + diff --git a/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java b/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java index cb50e815e39..fd97cddf9f3 100644 --- a/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java +++ b/repo/security-api/src/main/java/com/evolveum/midpoint/security/api/AuthorizationConstants.java @@ -36,8 +36,8 @@ public class AuthorizationConstants { public static final QName AUTZ_ALL_QNAME = new QName(NS_AUTHORIZATION, "all"); public static final String AUTZ_ALL_URL = QNameUtil.qNameToUri(AUTZ_ALL_QNAME); - public static final QName AUTZ_DEVEL_QNAME = new QName(NS_AUTHORIZATION, "devel"); - public static final String AUTZ_DEVEL_URL = NS_AUTHORIZATION + "#devel"; +// public static final QName AUTZ_DEVEL_QNAME = new QName(NS_AUTHORIZATION, "devel"); + public static final String AUTZ_NO_ACCESS_URL = NS_AUTHORIZATION + "#noAccess"; // public static final String AUTZ_DEVEL_URL = QNameUtil.qNameToUri(AUTZ_DEVEL_QNAME); public static final QName AUTZ_DENY_ALL_QNAME = new QName(NS_AUTHORIZATION, "denyAll"); diff --git a/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java b/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java index 96cdf8e6bcf..715846f8b29 100644 --- a/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java +++ b/repo/security-impl/src/main/java/com/evolveum/midpoint/security/impl/SecurityEnforcerImpl.java @@ -168,6 +168,11 @@ public boolean isAuthorized(String private boolean isAuthorizedInternal(MidPointPrincipal midPointPrincipal, String operationUrl, AuthorizationPhaseType phase, PrismObject object, ObjectDelta delta, PrismObject target, OwnerResolver ownerResolver) throws SchemaException { + + if (AuthorizationConstants.AUTZ_NO_ACCESS_URL.equals(operationUrl)){ + return false; + } + if (phase == null) { throw new IllegalArgumentException("No phase"); } @@ -181,6 +186,7 @@ private boolean isAuthorizedInterna if (authority instanceof Authorization) { Authorization autz = (Authorization)authority; LOGGER.trace("Evaluating authorization {}", autz); + // First check if the authorization is applicable. // action From 8e5432acaea3dce6f01baea8b9df6f7ee3d7d49d Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Mon, 21 Jul 2014 17:32:56 +0200 Subject: [PATCH 04/51] updated common-3 schema documentation.. (MID-1837) --- .../src/main/resources/xml/ns/public/common/common-3.xsd | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd index 51bee0ad800..68cba02dd8a 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd @@ -3234,7 +3234,7 @@ Defines a type from the resource schema (object class) that can be used for creating accounts, entitlements and possible other concepts. - This is abstract supertype for other types. + This is abstract supertype for other types. @@ -3242,12 +3242,13 @@ - + Specifies whether this type is the default type for the resource. - Only one type for each class can be default. Setting this flag for more than one type is - an error. + Only one type for each class can be default. Setting this flag to true for more than one type is + an error. If the flag is not set, the value is inherited from resource schema. If the resource + schema does not have this flag set, the default value is false. From 0d558bcd66a08b83379ce70d9eba26d1e8e200bc Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Mon, 21 Jul 2014 18:06:37 +0200 Subject: [PATCH 05/51] Fixing JAXB dependencies --- build-system/pom.xml | 15 +++++++++++++-- gui/admin-gui/pom.xml | 2 -- infra/ws-util/pom.xml | 4 ++-- model/model-client/pom.xml | 12 ++++++++++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/build-system/pom.xml b/build-system/pom.xml index 1b237133505..0bb2e61f5a8 100644 --- a/build-system/pom.xml +++ b/build-system/pom.xml @@ -48,8 +48,9 @@ 3.0.1.e1 3.0.1 2.4.7 - 2.2.7 - 2.2.7 + 2.2.9 + 2.2.10-b140310.1920 + 2.2.10-b140310.1920 4.8.2 2.4.3 1.8.5 @@ -178,11 +179,21 @@ je 4.1.10 + + jaxb-api + javax.xml.bind + ${jaxb-api.version} + com.sun.xml.bind jaxb-impl ${jaxb.version} + + com.sun.xml.bind + jaxb-core + ${jaxb.version} + com.sun.xsom xsom diff --git a/gui/admin-gui/pom.xml b/gui/admin-gui/pom.xml index 4d21267a6da..81cea65d3ff 100644 --- a/gui/admin-gui/pom.xml +++ b/gui/admin-gui/pom.xml @@ -594,12 +594,10 @@ jaxb-api javax.xml.bind - ${jaxb.version} jaxb-core com.sun.xml.bind - ${jaxb.version} diff --git a/infra/ws-util/pom.xml b/infra/ws-util/pom.xml index a05f74442b3..06d949bbfef 100644 --- a/infra/ws-util/pom.xml +++ b/infra/ws-util/pom.xml @@ -60,11 +60,11 @@ xml-resolver xml-resolver - + org.apache.cxf cxf-rt-ws-security diff --git a/model/model-client/pom.xml b/model/model-client/pom.xml index 200a01e26e0..b8c67e5afde 100644 --- a/model/model-client/pom.xml +++ b/model/model-client/pom.xml @@ -72,6 +72,18 @@ org.apache.cxf.xjc-utils cxf-xjc-runtime + + + org.apache.cxf + cxf-rt-frontend-jaxws + + + com.sun.xml.bind + jaxb-impl + + + com.sun.xml.bind + jaxb-core org.springframework From c24009add312324b80173cd8406c8ce9a47eadbb Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Tue, 22 Jul 2014 10:08:19 +0200 Subject: [PATCH 06/51] fixing MID-1975 (setting administrative status to undefined) --- .../impl/ResourceObjectConverter.java | 1 + .../ucf/impl/ConnectorInstanceIcfImpl.java | 47 +++++--- .../provisioning/test/impl/TestDummy.java | 103 +++++++++++++++++- 3 files changed, 136 insertions(+), 15 deletions(-) diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java index 01a129c0c84..f420719c204 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java @@ -806,6 +806,7 @@ private Collection determineActivationChange(ShadowType shadow, Colle } XMLGregorianCalendar xmlCal = validFromPropertyDelta.getPropertyNew().getRealValue(); LOGGER.trace("Found activation validFrom change to: {}", xmlCal); + //TODO: why this if?? do we really want to not allow to set validFrom/validTo to null value?? the same for validTo if (xmlCal != null) { operations.add(new PropertyModificationOperation(validFromPropertyDelta)); } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java index 8c4cef26aed..86451d76741 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java @@ -1419,22 +1419,28 @@ public Set modifyObject(ObjectClassComplexTypeDef try { updateAttributes = convertFromResourceObject(updateValues, result); + + if (activationDeltas != null) { + // Activation change means modification of attributes + convertFromActivation(updateAttributes, activationDeltas); + } + + if (passwordDelta != null) { + // Activation change means modification of attributes + convertFromPassword(updateAttributes, passwordDelta); + } + } catch (SchemaException ex) { result.recordFatalError( "Error while converting resource object attributes. Reason: " + ex.getMessage(), ex); throw new SchemaException("Error while converting resource object attributes. Reason: " + ex.getMessage(), ex); + } catch (RuntimeException ex) { + result.recordFatalError("Error while converting resource object attributes. Reason: " + ex.getMessage(), ex); + throw ex; } - if (activationDeltas != null) { - // Activation change means modification of attributes - convertFromActivation(updateAttributes, activationDeltas); - } - - if (passwordDelta != null) { - // Activation change means modification of attributes - convertFromPassword(updateAttributes, passwordDelta); - } + OperationOptions options = new OperationOptionsBuilder().build(); icfResult = result.createSubresult(ConnectorFacade.class.getName() + ".update"); @@ -2190,17 +2196,18 @@ private void convertFromActivation(Set updateAttributes, for (PropertyDelta propDelta : activationDeltas) { if (propDelta.getElementName().equals(ActivationType.F_ADMINISTRATIVE_STATUS)) { - ActivationStatusType status = propDelta.getPropertyNew().getValue(ActivationStatusType.class).getValue(); + ActivationStatusType status = getPropertyNewValue(propDelta, ActivationStatusType.class); + // Not entirely correct, TODO: refactor later updateAttributes.add(AttributeBuilder.build(OperationalAttributes.ENABLE_NAME, status == ActivationStatusType.ENABLED)); } else if (propDelta.getElementName().equals(ActivationType.F_VALID_FROM)) { - XMLGregorianCalendar xmlCal = propDelta.getPropertyNew().getValue(XMLGregorianCalendar.class).getValue(); + XMLGregorianCalendar xmlCal = getPropertyNewValue(propDelta, XMLGregorianCalendar.class);//propDelta.getPropertyNew().getValue(XMLGregorianCalendar.class).getValue(); updateAttributes.add(AttributeBuilder.build(OperationalAttributes.ENABLE_DATE_NAME, XmlTypeConverter.toMillis(xmlCal))); } else if (propDelta.getElementName().equals(ActivationType.F_VALID_TO)) { - XMLGregorianCalendar xmlCal = propDelta.getPropertyNew().getValue(XMLGregorianCalendar.class).getValue(); + XMLGregorianCalendar xmlCal = getPropertyNewValue(propDelta, XMLGregorianCalendar.class);//propDelta.getPropertyNew().getValue(XMLGregorianCalendar.class).getValue(); updateAttributes.add(AttributeBuilder.build(OperationalAttributes.DISABLE_DATE_NAME, XmlTypeConverter.toMillis(xmlCal))); } else if (propDelta.getElementName().equals(ActivationType.F_LOCKOUT_STATUS)) { - LockoutStatusType status = propDelta.getPropertyNew().getValue(LockoutStatusType.class).getValue(); + LockoutStatusType status = getPropertyNewValue(propDelta, LockoutStatusType.class);//propDelta.getPropertyNew().getValue(LockoutStatusType.class).getValue(); updateAttributes.add(AttributeBuilder.build(OperationalAttributes.LOCK_OUT_NAME, status != LockoutStatusType.NORMAL)); } else { throw new SchemaException("Got unknown activation attribute delta " + propDelta.getElementName()); @@ -2209,6 +2216,20 @@ private void convertFromActivation(Set updateAttributes, } + private T getPropertyNewValue(PropertyDelta propertyDelta, Class clazz) throws SchemaException { + PrismProperty> prop = propertyDelta.getPropertyNew(); + if (prop == null){ + return null; + } + PrismPropertyValue propValue = prop.getValue(clazz); + + if (propValue == null){ + return null; + } + + return propValue.getValue(); + } + private void convertFromPassword(Set attributes, PropertyDelta passwordDelta) throws SchemaException { if (passwordDelta == null) { throw new IllegalArgumentException("No password was provided"); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java index 9857445012a..620fb003029 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java @@ -62,6 +62,7 @@ import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.prism.PrismPropertyDefinition; import com.evolveum.midpoint.prism.PrismPropertyValue; @@ -1888,8 +1889,8 @@ public void test135ExecuteScript() throws Exception { assertSteadyResource(); } - - @Test + + @Test public void test150DisableAccount() throws Exception { final String TEST_NAME = "test150DisableAccount"; TestUtil.displayTestTile(TEST_NAME); @@ -1933,6 +1934,50 @@ public void test150DisableAccount() throws Exception { assertSteadyResource(); } + + @Test + public void test151ActivationStatusUndefinedAccount() throws Exception { + final String TEST_NAME = "test151ActivationStatusUndefinedAccount"; + TestUtil.displayTestTile(TEST_NAME); + // GIVEN + + Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + ShadowType accountType = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, task, + result).asObjectable(); + assertNotNull(accountType); + display("Retrieved account shadow", accountType); + + DummyAccount dummyAccount = getDummyAccountAssert(ACCOUNT_WILL_USERNAME, willIcfUid); + assertFalse("Account is not disabled", dummyAccount.isEnabled()); + + syncServiceMock.reset(); + + ObjectDelta delta = ObjectDelta.createModificationDeleteProperty(ShadowType.class, + ACCOUNT_WILL_OID, SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS, prismContext, + ActivationStatusType.DISABLED); + display("ObjectDelta", delta); + delta.checkConsistence(); + + // WHEN + provisioningService.modifyObject(ShadowType.class, delta.getOid(), delta.getModifications(), + new OperationProvisioningScriptsType(), null, task, result); + + // THEN + result.computeStatus(); + display("modifyObject result", result); + TestUtil.assertSuccess(result); + + delta.checkConsistence(); + // check if activation was changed + dummyAccount = getDummyAccountAssert(ACCOUNT_WILL_USERNAME, willIcfUid); + assertFalse("Dummy account "+ACCOUNT_WILL_USERNAME+" is enabled, expected disabled", dummyAccount.isEnabled()); + + syncServiceMock.assertNotifySuccessOnly(); + + assertSteadyResource(); + } @Test public void test151EnableAccount() throws Exception { @@ -1978,6 +2023,8 @@ public void test151EnableAccount() throws Exception { assertSteadyResource(); } + + @Test public void test152SetValidFrom() throws Exception { final String TEST_NAME = "test152SetValidFrom"; @@ -2073,6 +2120,58 @@ public void test153SetValidTo() throws Exception { assertSteadyResource(); } + //TODO: if this needed?? for now, we don't allow to set activation valid from and valid to to null value... + @Test(enabled = false) + public void test154DeleteValidToValidFrom() throws Exception { + final String TEST_NAME = "test154DeleteValidToValidFrom"; + TestUtil.displayTestTile(TEST_NAME); + // GIVEN + + Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + ShadowType accountType = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, task, + result).asObjectable(); + assertNotNull(accountType); + + display("Retrieved account shadow", accountType); + + DummyAccount dummyAccount = getDummyAccountAssert(ACCOUNT_WILL_USERNAME, willIcfUid); + assertTrue(dummyAccount.isEnabled()); + + syncServiceMock.reset(); + +// long millis = VALID_TO_MILLIS; + + ObjectDelta delta = ObjectDelta.createModificationDeleteProperty(ShadowType.class, + ACCOUNT_WILL_OID, SchemaConstants.PATH_ACTIVATION_VALID_TO, prismContext, + XmlTypeConverter.createXMLGregorianCalendar(VALID_TO_MILLIS)); + PrismObjectDefinition def = accountType.asPrismObject().getDefinition(); + PropertyDelta validFromDelta = PropertyDelta.createModificationDeleteProperty(SchemaConstants.PATH_ACTIVATION_VALID_FROM, def.findPropertyDefinition(SchemaConstants.PATH_ACTIVATION_VALID_FROM), VALID_FROM_MILLIS); + delta.addModification(validFromDelta); + delta.checkConsistence(); + + // WHEN + provisioningService.modifyObject(ShadowType.class, delta.getOid(), + delta.getModifications(), new OperationProvisioningScriptsType(), null, task, result); + + // THEN + result.computeStatus(); + display("modifyObject result", result); + TestUtil.assertSuccess(result); + + delta.checkConsistence(); + // check if activation was changed + dummyAccount = getDummyAccountAssert(ACCOUNT_WILL_USERNAME, willIcfUid); + assertNull("Wrong account validTo in account "+ACCOUNT_WILL_USERNAME + ": " + dummyAccount.getValidTo(), dummyAccount.getValidTo()); + assertNull("Wrong account validFrom in account "+ACCOUNT_WILL_USERNAME + ": " + dummyAccount.getValidFrom(), dummyAccount.getValidFrom()); + assertTrue("Dummy account "+ACCOUNT_WILL_USERNAME+" is disabled, expected enabled", dummyAccount.isEnabled()); + + syncServiceMock.assertNotifySuccessOnly(); + + assertSteadyResource(); + } + @Test public void test155GetLockedoutAccount() throws Exception { final String TEST_NAME = "test155GetLockedoutAccount"; From 5d4a2c22b1b083a300590484e9fcd7f10f1e7b37 Mon Sep 17 00:00:00 2001 From: Erik Suta Date: Tue, 22 Jul 2014 10:50:40 +0200 Subject: [PATCH 07/51] Fix for security issue on SystemConfiguration page --- .../configuration/PageSystemConfiguration.java | 10 ++++++---- .../component/SystemConfigPanel.html | 3 +-- .../component/SystemConfigPanel.java | 11 ++++++++++- .../component/SystemConfigPanel.properties | 2 ++ .../dto/NotificationConfigurationDto.java | 13 +++---------- .../dto/SystemConfigurationDto.java | 18 +++++++++--------- 6 files changed, 31 insertions(+), 26 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageSystemConfiguration.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageSystemConfiguration.java index dc9e5f4c21a..973101b07a2 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageSystemConfiguration.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageSystemConfiguration.java @@ -112,7 +112,7 @@ private SystemConfigurationDto loadSystemConfiguration() { PrismObject systemConfig = getModelService().getObject(SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), options, task, result); - dto = new SystemConfigurationDto(systemConfig, getMidpointApplication().getProtector()); + dto = new SystemConfigurationDto(systemConfig); result.recordSuccess(); } catch(Exception ex){ LoggingUtils.logException(LOGGER, "Couldn't load system configuration", ex); @@ -399,9 +399,11 @@ private SystemConfigurationType saveNotificationConfiguration(SystemConfiguratio mailServerConfig.setUsername(dto.getUsername()); mailServerConfig.setTransportSecurity(dto.getMailTransportSecurityType()); - ProtectedStringType pass = new ProtectedStringType(); - pass.setClearValue(dto.getPassword()); - mailServerConfig.setPassword(pass); + if(dto.getPassword() != null && StringUtils.isNotEmpty(dto.getPassword())){ + ProtectedStringType pass = new ProtectedStringType(); + pass.setClearValue(dto.getPassword()); + mailServerConfig.setPassword(pass); + } if(mailConfig.getServer().isEmpty()){ if(dto.isConfigured()) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.html index 0723db5670b..6075c9e1507 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.html @@ -153,8 +153,7 @@

- +

diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.java index c92e089f1b2..b703f043070 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.java @@ -26,6 +26,7 @@ import com.evolveum.midpoint.web.util.InfoTooltipBehavior; import com.evolveum.midpoint.web.util.WebMiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.MailTransportSecurityType; +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.form.*; @@ -101,7 +102,15 @@ protected void initLayout(){ TextField userNameField = new TextField<>(ID_USERNAME, new PropertyModel(getModel(), "notificationConfig.username")); PasswordTextField passwordField = new PasswordTextField(ID_PASSWORD, new PropertyModel(getModel(), "notificationConfig.password")); passwordField.setRequired(false); - passwordField.setResetPassword(false); + + if(getModel().getObject() != null){ + if(getModel().getObject().getNotificationConfig().getPassword() != null){ + passwordField.add(new AttributeAppender("placeholder", createStringResource("SystemConfigPanel.mail.password.placeholder.set"))); + } else { + passwordField.add(new AttributeAppender("placeholder", createStringResource("SystemConfigPanel.mail.password.placeholder.empty"))); + } + } + TextField redirectToFileField = new TextField<>(ID_REDIRECT_TO_FILE, new PropertyModel(getModel(), "notificationConfig.redirectToFile")); IModel choices = WebMiscUtil.createReadonlyModelFromEnum(MailTransportSecurityType.class); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.properties index 30c857ae046..47ce986e1c9 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/SystemConfigPanel.properties @@ -31,6 +31,8 @@ SystemConfigPanel.mail.host=Host SystemConfigPanel.mail.port=Port SystemConfigPanel.mail.username=Username SystemConfigPanel.mail.password=Password +SystemConfigPanel.mail.password.placeholder.empty=Set password +SystemConfigPanel.mail.password.placeholder.set=Password is set SystemConfigPanel.mail.transportSecurity=Transport security SystemConfigPanel.notification.redirectToFile=Redirect to file SystemConfigPanel.notification.redirectToFile.placeholder=Filename diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/dto/NotificationConfigurationDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/dto/NotificationConfigurationDto.java index 113400fea80..02283064dee 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/dto/NotificationConfigurationDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/dto/NotificationConfigurationDto.java @@ -15,16 +15,13 @@ */ package com.evolveum.midpoint.web.page.admin.configuration.dto; -import com.evolveum.midpoint.prism.crypto.Protector; -import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.web.util.WebMiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.MailConfigurationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.MailServerConfigurationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.MailTransportSecurityType; import com.evolveum.midpoint.xml.ns._public.common.common_3.NotificationConfigurationType; -import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; + import java.io.Serializable; @@ -48,7 +45,7 @@ public class NotificationConfigurationDto implements Serializable{ public NotificationConfigurationDto(){} - public NotificationConfigurationDto(NotificationConfigurationType config, Protector protector){ + public NotificationConfigurationDto(NotificationConfigurationType config){ if(config.getMail() != null){ MailConfigurationType mailConfig = config.getMail(); @@ -71,11 +68,7 @@ public NotificationConfigurationDto(NotificationConfigurationType config, Protec username = serverConfig.getUsername(); if(serverConfig.getPassword() != null){ - try { - password = protector.decryptString(serverConfig.getPassword()); - } catch (Exception e){ - LoggingUtils.logException(LOGGER, "Unable to decrypt password in mail configuration.", e); - } + password = "Set"; } else { password = null; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/dto/SystemConfigurationDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/dto/SystemConfigurationDto.java index 06f1a9a9fb7..24a51be0382 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/dto/SystemConfigurationDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/dto/SystemConfigurationDto.java @@ -39,14 +39,14 @@ public class SystemConfigurationDto implements Serializable { private NotificationConfigurationDto notificationConfig; public SystemConfigurationDto(){ - this(null, null); + this(null); } - public SystemConfigurationDto(PrismObject config, Protector protector) { - init(config.asObjectable(), protector); + public SystemConfigurationDto(PrismObject config) { + init(config.asObjectable()); } - private void init(SystemConfigurationType config, Protector protector){ + private void init(SystemConfigurationType config){ if(config == null){ return; } @@ -66,7 +66,7 @@ private void init(SystemConfigurationType config, Protector protector){ objectTemplateDto = loadObjectTemplate(config); if(config.getNotificationConfiguration() != null){ - notificationConfig = new NotificationConfigurationDto(config.getNotificationConfiguration(), protector); + notificationConfig = new NotificationConfigurationDto(config.getNotificationConfiguration()); } else { notificationConfig = new NotificationConfigurationDto(); } @@ -76,9 +76,9 @@ private ObjectViewDto loadPasswordPolicy(SystemConfigurationTyp ValuePolicyType passPolicy = config.getGlobalPasswordPolicy(); if(passPolicy != null){ - passPolicyDto = new ObjectViewDto(passPolicy.getOid(), passPolicy.getName().getOrig()); + passPolicyDto = new ObjectViewDto<>(passPolicy.getOid(), passPolicy.getName().getOrig()); }else { - passPolicyDto = new ObjectViewDto(); + passPolicyDto = new ObjectViewDto<>(); } passPolicyDto.setType(ValuePolicyType.class); @@ -89,9 +89,9 @@ private ObjectViewDto loadObjectTemplate(SystemConfiguration ObjectTemplateType objectTemplate = config.getDefaultUserTemplate(); if(objectTemplate != null){ - objectTemplateDto = new ObjectViewDto(objectTemplate.getOid(), objectTemplate.getName().getOrig()); + objectTemplateDto = new ObjectViewDto<>(objectTemplate.getOid(), objectTemplate.getName().getOrig()); }else { - objectTemplateDto = new ObjectViewDto(); + objectTemplateDto = new ObjectViewDto<>(); } objectTemplateDto.setType(ObjectTemplateType.class); From fbda2ce99faf41f0b669901bf4c8bffd3819aba5 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Tue, 22 Jul 2014 12:11:05 +0200 Subject: [PATCH 08/51] adding support to delete validTo validFrom activation times + fixing tests.. --- .../icf/dummy/connector/DummyConnector.java | 5 + .../midpoint/prism/xml/XmlTypeConverter.java | 3 + .../impl/ResourceObjectConverter.java | 7 +- .../ucf/impl/ConnectorInstanceIcfImpl.java | 4 +- .../provisioning/test/impl/TestDummy.java | 3 +- .../test/impl/TestDummyNoActivation.java | 94 +++++++++++++++++++ 6 files changed, 106 insertions(+), 10 deletions(-) diff --git a/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConnector.java b/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConnector.java index 717cb7223ea..2d5e436ae0f 100644 --- a/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConnector.java +++ b/icf-connectors/dummy-connector/src/main/java/com/evolveum/icf/dummy/connector/DummyConnector.java @@ -1269,6 +1269,11 @@ private Date getDate(Attribute attr) { throw new IllegalArgumentException("Empty date attribute was provided"); } Object object = attr.getValue().get(0); + + if (object == null){ + return null; + } + if (!(object instanceof Long)) { throw new IllegalArgumentException("Date attribute was provided as "+object.getClass().getName()+" while expecting long"); } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/xml/XmlTypeConverter.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/xml/XmlTypeConverter.java index 0756f279468..d85c11b35c2 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/xml/XmlTypeConverter.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/xml/XmlTypeConverter.java @@ -479,6 +479,9 @@ public static XMLGregorianCalendar createXMLGregorianCalendar(int year, int mont } public static long toMillis(XMLGregorianCalendar xmlCal) { + if (xmlCal == null){ + return 0; + } return xmlCal.toGregorianCalendar().getTimeInMillis(); } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java index f420719c204..04f1d9310cf 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java @@ -806,10 +806,7 @@ private Collection determineActivationChange(ShadowType shadow, Colle } XMLGregorianCalendar xmlCal = validFromPropertyDelta.getPropertyNew().getRealValue(); LOGGER.trace("Found activation validFrom change to: {}", xmlCal); - //TODO: why this if?? do we really want to not allow to set validFrom/validTo to null value?? the same for validTo - if (xmlCal != null) { - operations.add(new PropertyModificationOperation(validFromPropertyDelta)); - } + operations.add(new PropertyModificationOperation(validFromPropertyDelta)); } // validTo @@ -821,9 +818,7 @@ private Collection determineActivationChange(ShadowType shadow, Colle } XMLGregorianCalendar xmlCal = validToPropertyDelta.getPropertyNew().getRealValue(); LOGGER.trace("Found activation validTo change to: {}", xmlCal); - if (xmlCal != null) { operations.add(new PropertyModificationOperation(validToPropertyDelta)); - } } PropertyDelta lockoutPropertyDelta = PropertyDelta.findPropertyDelta(objectChange, diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java index 86451d76741..bced2152cb6 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java @@ -2202,10 +2202,10 @@ private void convertFromActivation(Set updateAttributes, updateAttributes.add(AttributeBuilder.build(OperationalAttributes.ENABLE_NAME, status == ActivationStatusType.ENABLED)); } else if (propDelta.getElementName().equals(ActivationType.F_VALID_FROM)) { XMLGregorianCalendar xmlCal = getPropertyNewValue(propDelta, XMLGregorianCalendar.class);//propDelta.getPropertyNew().getValue(XMLGregorianCalendar.class).getValue(); - updateAttributes.add(AttributeBuilder.build(OperationalAttributes.ENABLE_DATE_NAME, XmlTypeConverter.toMillis(xmlCal))); + updateAttributes.add(AttributeBuilder.build(OperationalAttributes.ENABLE_DATE_NAME, xmlCal != null ? XmlTypeConverter.toMillis(xmlCal) : null)); } else if (propDelta.getElementName().equals(ActivationType.F_VALID_TO)) { XMLGregorianCalendar xmlCal = getPropertyNewValue(propDelta, XMLGregorianCalendar.class);//propDelta.getPropertyNew().getValue(XMLGregorianCalendar.class).getValue(); - updateAttributes.add(AttributeBuilder.build(OperationalAttributes.DISABLE_DATE_NAME, XmlTypeConverter.toMillis(xmlCal))); + updateAttributes.add(AttributeBuilder.build(OperationalAttributes.DISABLE_DATE_NAME, xmlCal != null ? XmlTypeConverter.toMillis(xmlCal) : null)); } else if (propDelta.getElementName().equals(ActivationType.F_LOCKOUT_STATUS)) { LockoutStatusType status = getPropertyNewValue(propDelta, LockoutStatusType.class);//propDelta.getPropertyNew().getValue(LockoutStatusType.class).getValue(); updateAttributes.add(AttributeBuilder.build(OperationalAttributes.LOCK_OUT_NAME, status != LockoutStatusType.NORMAL)); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java index 620fb003029..635dfbca71c 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummy.java @@ -2120,8 +2120,7 @@ public void test153SetValidTo() throws Exception { assertSteadyResource(); } - //TODO: if this needed?? for now, we don't allow to set activation valid from and valid to to null value... - @Test(enabled = false) + @Test public void test154DeleteValidToValidFrom() throws Exception { final String TEST_NAME = "test154DeleteValidToValidFrom"; TestUtil.displayTestTile(TEST_NAME); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummyNoActivation.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummyNoActivation.java index 2f599b72c6c..b0e09b073d3 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummyNoActivation.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/impl/TestDummyNoActivation.java @@ -32,7 +32,9 @@ import org.testng.annotations.Test; import com.evolveum.icf.dummy.resource.DummyAccount; +import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.delta.PropertyDelta; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; @@ -124,6 +126,49 @@ public void test150DisableAccount() throws Exception { assertSteadyResource(); } + @Override + public void test151ActivationStatusUndefinedAccount() throws Exception { + final String TEST_NAME = "test151EnableAccount"; + TestUtil.displayTestTile(TEST_NAME); + // GIVEN + + Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + syncServiceMock.reset(); + + ObjectDelta delta = ObjectDelta.createModificationDeleteProperty(ShadowType.class, + ACCOUNT_WILL_OID, SchemaConstants.PATH_ACTIVATION_ADMINISTRATIVE_STATUS, prismContext, + ActivationStatusType.DISABLED); + display("ObjectDelta", delta); + delta.checkConsistence(); + + + try { + // WHEN + provisioningService.modifyObject(ShadowType.class, delta.getOid(), + delta.getModifications(), new OperationProvisioningScriptsType(), null, task, result); + + AssertJUnit.fail("Unexpected success"); + } catch (SchemaException e) { + // This is expected + + } + + // THEN + result.computeStatus(); + display("modifyObject result", result); + TestUtil.assertFailure(result); + + delta.checkConsistence(); + // check if activation was unchanged + DummyAccount dummyAccount = dummyResource.getAccountByUsername(ACCOUNT_WILL_USERNAME); + assertTrue("Dummy account "+ACCOUNT_WILL_USERNAME+" is disabled, expected enabled", dummyAccount.isEnabled()); + + syncServiceMock.assertNotifyFailureOnly(); + + assertSteadyResource(); + } + @Test @Override public void test151EnableAccount() throws Exception { @@ -260,6 +305,55 @@ public void test153SetValidTo() throws Exception { assertSteadyResource(); } + @Override + public void test154DeleteValidToValidFrom() throws Exception { + final String TEST_NAME = "test153SetValidTo"; + TestUtil.displayTestTile(TEST_NAME); + // GIVEN + + Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + syncServiceMock.reset(); + + + ObjectDelta delta = ObjectDelta.createModificationDeleteProperty(ShadowType.class, + ACCOUNT_WILL_OID, SchemaConstants.PATH_ACTIVATION_VALID_TO, prismContext, + XmlTypeConverter.createXMLGregorianCalendar(VALID_TO_MILLIS)); + PrismObjectDefinition def = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class); + PropertyDelta validFromDelta = PropertyDelta.createModificationDeleteProperty(SchemaConstants.PATH_ACTIVATION_VALID_FROM, def.findPropertyDefinition(SchemaConstants.PATH_ACTIVATION_VALID_FROM), VALID_FROM_MILLIS); + delta.addModification(validFromDelta); + delta.checkConsistence(); + + + try { + // WHEN + provisioningService.modifyObject(ShadowType.class, delta.getOid(), + delta.getModifications(), new OperationProvisioningScriptsType(), null, task, result); + + AssertJUnit.fail("Unexpected success"); + } catch (SchemaException e) { + // This is expected + + } + + // THEN + result.computeStatus(); + display("modifyObject result", result); + TestUtil.assertFailure(result); + + delta.checkConsistence(); + // check if activation was changed + DummyAccount dummyAccount = dummyResource.getAccountByUsername(ACCOUNT_WILL_USERNAME); + assertTrue("Dummy account "+ACCOUNT_WILL_USERNAME+" is disabled, expected enabled", dummyAccount.isEnabled()); + assertNull("Unexpected account validFrom in account "+ACCOUNT_WILL_USERNAME+": "+dummyAccount.getValidFrom(), dummyAccount.getValidFrom()); + assertNull("Unexpected account validTo in account "+ACCOUNT_WILL_USERNAME+": "+dummyAccount.getValidTo(), dummyAccount.getValidTo()); + + syncServiceMock.assertNotifyFailureOnly(); + + assertSteadyResource(); + + } + @Test @Override public void test155GetLockedoutAccount() throws Exception { From eb79d5c6eeade1cbab1f58ce4ff3578618f19d65 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Tue, 22 Jul 2014 13:27:06 +0200 Subject: [PATCH 09/51] updated security handlers for REST after cxf upgrade.. --- .../security/MidpointRestAuthenticationHandler.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticationHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticationHandler.java index 7ba5a805d09..b5090383f6e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticationHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/MidpointRestAuthenticationHandler.java @@ -27,6 +27,7 @@ import org.apache.cxf.configuration.security.AuthorizationPolicy; import org.apache.cxf.jaxrs.model.ClassResourceInfo; import org.apache.cxf.jaxrs.model.OperationResourceInfo; +import org.apache.cxf.jaxrs.utils.JAXRSUtils; import org.apache.cxf.message.Message; import org.springframework.beans.factory.annotation.Autowired; @@ -51,7 +52,7 @@ public class MidpointRestAuthenticationHandler implements ContainerRequestFilter @Autowired(required = true) private Protector protector; - public Response handleRequest(Message m, ClassResourceInfo resourceClass) { + public Response handleRequest(Message m) { AuthorizationPolicy policy = (AuthorizationPolicy)m.get(AuthorizationPolicy.class); OperationResourceInfo ori = m.getExchange().get(OperationResourceInfo.class); @@ -137,20 +138,24 @@ public Response handleRequest(Message m, ClassResourceInfo resourceClass) { } // // @Override -// public Response handleResponse(Message m, OperationResourceInfo ori, Response response) { +// public Response handleResponse(Message m, Response response) { // securityEnforcer.setupPreAuthenticatedSecurityContext((PrismObject) null); // return null; // } @Override public void filter(ContainerRequestContext arg0, ContainerResponseContext arg1) throws IOException { - // TODO Auto-generated method stub + Message m = JAXRSUtils.getCurrentMessage(); + handleRequest(m); + +// handleResponse(m, ori, response) } @Override public void filter(ContainerRequestContext arg0) throws IOException { - // TODO Auto-generated method stub + Message m = JAXRSUtils.getCurrentMessage(); + handleRequest(m); } From cf5d8cafd0a83ade383b9f6093b9c6d7bea3a49c Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Tue, 22 Jul 2014 14:07:15 +0200 Subject: [PATCH 10/51] Authentication exceptions for web service and rest service --- gui/admin-gui/src/main/webapp/WEB-INF/ctx-web-security.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gui/admin-gui/src/main/webapp/WEB-INF/ctx-web-security.xml b/gui/admin-gui/src/main/webapp/WEB-INF/ctx-web-security.xml index 8c9002ba51d..efccb8c3a63 100644 --- a/gui/admin-gui/src/main/webapp/WEB-INF/ctx-web-security.xml +++ b/gui/admin-gui/src/main/webapp/WEB-INF/ctx-web-security.xml @@ -26,7 +26,12 @@ http://www.springframework.org/schema/security/spring-security-3.1.xsd"> + + + + + From 5c702677f306182c87b8aa824121a622b2c22778 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Tue, 22 Jul 2014 14:14:54 +0200 Subject: [PATCH 11/51] Support for authentication mechanism selection using command-line --- .../wsutil/AbstractWebServiceClient.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/infra/ws-util/src/main/java/com/evolveum/midpoint/infra/wsutil/AbstractWebServiceClient.java b/infra/ws-util/src/main/java/com/evolveum/midpoint/infra/wsutil/AbstractWebServiceClient.java index dc4d70606b6..5d0af12d6fb 100644 --- a/infra/ws-util/src/main/java/com/evolveum/midpoint/infra/wsutil/AbstractWebServiceClient.java +++ b/infra/ws-util/src/main/java/com/evolveum/midpoint/infra/wsutil/AbstractWebServiceClient.java @@ -94,6 +94,7 @@ public void main(String[] args) { } protected void init(String[] args) throws ParseException { + options.addOption("a", "authentication", true, "Authentication type ("+WSHandlerConstants.USERNAME_TOKEN+", none)"); options.addOption("u", "user", true, "Username"); options.addOption("p", "password", true, "Password"); options.addOption("P", "password-type", true, "Password type (text or digest)"); @@ -164,14 +165,22 @@ protected P createPort() throws Exception { Map wssProps = new HashMap(); - wssProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN); - wssProps.put(WSHandlerConstants.USER, username); - wssProps.put(WSHandlerConstants.PASSWORD_TYPE, getPasswordType()); - wssProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordHandler.class.getName()); - ClientPasswordHandler.setPassword(password); + if (!commandLine.hasOption('a') || + (commandLine.hasOption('a') && WSHandlerConstants.USERNAME_TOKEN.equals(commandLine.getOptionValue('a')))) { - WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(wssProps); - cxfEndpoint.getOutInterceptors().add(wssOut); + wssProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN); + wssProps.put(WSHandlerConstants.USER, username); + wssProps.put(WSHandlerConstants.PASSWORD_TYPE, getPasswordType()); + wssProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordHandler.class.getName()); + ClientPasswordHandler.setPassword(password); + + WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(wssProps); + cxfEndpoint.getOutInterceptors().add(wssOut); + } else if (commandLine.hasOption('a') && "none".equals(commandLine.getOptionValue('a'))) { + // Nothing to do + } else { + throw new IllegalArgumentException("Unknown authentication mechanism '"+commandLine.getOptionValue('a')+"'"); + } if (commandLine.hasOption('m')) { cxfEndpoint.getInInterceptors().add(new LoggingInInterceptor()); From 4c05eb2192b3b857f2ece2aef55f1084648838a2 Mon Sep 17 00:00:00 2001 From: Erik Suta Date: Tue, 22 Jul 2014 14:28:14 +0200 Subject: [PATCH 12/51] MID-1981 fix - admin. is now able to edit resource reference in existing tasks in GUI. --- .../web/page/admin/server/PageTaskEdit.html | 4 + .../web/page/admin/server/PageTaskEdit.java | 85 ++++++++++++++++--- .../page/admin/server/PageTaskEdit.properties | 1 + .../web/page/admin/server/dto/TaskDto.java | 22 +++++ 4 files changed, 102 insertions(+), 10 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.html index 3097922340b..2a694e00495 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.html @@ -55,6 +55,10 @@

+ + + + + + + diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskAdd.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskAdd.java index 44dad83cb8a..a9341705db0 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskAdd.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskAdd.java @@ -47,6 +47,7 @@ import com.evolveum.midpoint.web.util.WebMiscUtil; 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.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.markup.html.form.AjaxCheckBox; @@ -80,6 +81,30 @@ public class PageTaskAdd extends PageAdminTasks { private static final long serialVersionUID = 2317887071933841581L; private static final String ID_DRY_RUN = "dryRun"; + private static final String ID_KIND = "kind"; + private static final String ID_INTENT = "intent"; + private static final String ID_FORM_MAIN = "mainForm"; + private static final String ID_NAME = "name"; + private static final String ID_CATEGORY = "category"; + private static final String ID_RESOURCE = "resource"; + private static final String ID_RUN_UNTIL_NODW_DOWN = "runUntilNodeDown"; + private static final String ID_CREATE_SUSPENDED = "createSuspended"; + private static final String ID_THREAD_STOP = "threadStop"; + private static final String ID_MISFIRE_ACTION = "misfireAction"; + private static final String ID_RECURRING = "recurring"; + private static final String ID_CONTAINER = "container"; + private static final String ID_BOUND_CONTAINER = "boundContainer"; + private static final String ID_BOUND_HELP = "boundHelp"; + private static final String ID_BOUND = "bound"; + private static final String ID_INTERVAL_CONTAINER = "intervalContainer"; + private static final String ID_INTERVAL = "interval"; + private static final String ID_CRON_CONTAINER = "cronContainer"; + private static final String ID_CRON = "cron"; + private static final String ID_CRON_HELP = "cronHelp"; + private static final String ID_NO_START_BEFORE_FIELD = "notStartBeforeField"; + private static final String ID_NO_START_AFTER_FIELD = "notStartAfterField"; + private static final String ID_BUTTON_BACK = "backButton"; + private static final String ID_BUTTON_SAVE = "saveButton"; private static final Trace LOGGER = TraceManager.getTrace(PageTaskAdd.class); private static final String DOT_CLASS = PageTaskAdd.class.getName() + "."; @@ -103,11 +128,11 @@ private TaskAddDto loadTask() { } private void initLayout() { - Form mainForm = new Form("mainForm"); + Form mainForm = new Form(ID_FORM_MAIN); add(mainForm); - final DropDownChoice resource = new DropDownChoice("resource", - new PropertyModel(model, "resource"), + final DropDownChoice resource = new DropDownChoice(ID_RESOURCE, + new PropertyModel(model, TaskAddDto.F_RESOURCE), new AbstractReadOnlyModel>() { @Override @@ -125,8 +150,7 @@ public Object getDisplayValue(TaskAddResourcesDto dto) { public String getIdValue(TaskAddResourcesDto dto, int index) { return Integer.toString(index); } - } - ); + }); resource.add(new VisibleEnableBehaviour() { @Override @@ -140,7 +164,51 @@ public boolean isEnabled() { }); resource.setOutputMarkupId(true); mainForm.add(resource); - DropDownChoice type = new DropDownChoice("category", new PropertyModel(model, "category"), + + final DropDownChoice kind = new DropDownChoice(ID_KIND, + new PropertyModel(model, TaskAddDto.F_KIND), + new AbstractReadOnlyModel>() { + + @Override + public List getObject() { + return createShadowKindTypeList(); + } + }, new IChoiceRenderer() { + + @Override + public Object getDisplayValue(ShadowKindType object) { + return object.value(); + } + + @Override + public String getIdValue(ShadowKindType object, int index) { + return Integer.toString(index); + } + }); + kind.setOutputMarkupId(true); + kind.add(new VisibleEnableBehaviour(){ + + @Override + public boolean isEnabled() { + TaskAddDto dto = model.getObject(); + return TaskCategory.RECONCILIATION.equals(dto.getCategory()); + } + }); + mainForm.add(kind); + + final TextField intent = new TextField<>(ID_INTENT, new PropertyModel(model, TaskAddDto.F_INTENT)); + mainForm.add(intent); + intent.setOutputMarkupId(true); + intent.add(new VisibleEnableBehaviour(){ + + @Override + public boolean isEnabled() { + TaskAddDto dto = model.getObject(); + return TaskCategory.RECONCILIATION.equals(dto.getCategory()); + } + }); + + DropDownChoice type = new DropDownChoice(ID_CATEGORY, new PropertyModel(model, TaskAddDto.F_CATEGORY), new AbstractReadOnlyModel>() { @Override @@ -158,20 +226,20 @@ public Object getDisplayValue(String item) { public String getIdValue(String item, int index) { return Integer.toString(index); } - - } - ); + }); type.add(new AjaxFormComponentUpdatingBehavior("onChange") { @Override protected void onUpdate(AjaxRequestTarget target) { target.add(resource); + target.add(intent); + target.add(kind); } }); type.setRequired(true); mainForm.add(type); - TextField name = new TextField("name", new PropertyModel(model, "name")); + TextField name = new TextField<>(ID_NAME, new PropertyModel(model, TaskAddDto.F_NAME)); name.setRequired(true); mainForm.add(name); @@ -185,14 +253,14 @@ protected void onUpdate(AjaxRequestTarget target) { } private void initScheduling(final Form mainForm) { - final WebMarkupContainer container = new WebMarkupContainer("container"); + final WebMarkupContainer container = new WebMarkupContainer(ID_CONTAINER); container.setOutputMarkupId(true); mainForm.add(container); - final IModel recurringCheck = new PropertyModel(model, "reccuring"); - final IModel boundCheck = new PropertyModel(model, "bound"); + final IModel recurringCheck = new PropertyModel<>(model, TaskAddDto.F_RECURRING); + final IModel boundCheck = new PropertyModel<>(model, TaskAddDto.F_BOUND); - final WebMarkupContainer boundContainer = new WebMarkupContainer("boundContainer"); + final WebMarkupContainer boundContainer = new WebMarkupContainer(ID_BOUND_CONTAINER); boundContainer.add(new VisibleEnableBehaviour() { @Override @@ -204,7 +272,7 @@ public boolean isVisible() { boundContainer.setOutputMarkupId(true); container.add(boundContainer); - final WebMarkupContainer intervalContainer = new WebMarkupContainer("intervalContainer"); + final WebMarkupContainer intervalContainer = new WebMarkupContainer(ID_INTERVAL_CONTAINER); intervalContainer.add(new VisibleEnableBehaviour() { @Override @@ -216,7 +284,7 @@ public boolean isVisible() { intervalContainer.setOutputMarkupId(true); container.add(intervalContainer); - final WebMarkupContainer cronContainer = new WebMarkupContainer("cronContainer"); + final WebMarkupContainer cronContainer = new WebMarkupContainer(ID_CRON_CONTAINER); cronContainer.add(new VisibleEnableBehaviour() { @Override @@ -228,7 +296,7 @@ public boolean isVisible() { cronContainer.setOutputMarkupId(true); container.add(cronContainer); - AjaxCheckBox recurring = new AjaxCheckBox("recurring", recurringCheck) { + AjaxCheckBox recurring = new AjaxCheckBox(ID_RECURRING, recurringCheck) { @Override protected void onUpdate(AjaxRequestTarget target) { @@ -237,7 +305,7 @@ protected void onUpdate(AjaxRequestTarget target) { }; mainForm.add(recurring); - AjaxCheckBox bound = new AjaxCheckBox("bound", boundCheck) { + AjaxCheckBox bound = new AjaxCheckBox(ID_BOUND, boundCheck) { @Override protected void onUpdate(AjaxRequestTarget target) { @@ -246,29 +314,29 @@ protected void onUpdate(AjaxRequestTarget target) { }; boundContainer.add(bound); - Label boundHelp = new Label("boundHelp"); + Label boundHelp = new Label(ID_BOUND_HELP); boundHelp.add(new InfoTooltipBehavior()); boundContainer.add(boundHelp); - TextField interval = new TextField("interval", - new PropertyModel(model, "interval")); + TextField interval = new TextField<>(ID_INTERVAL, + new PropertyModel(model, TaskAddDto.F_INTERVAL)); interval.add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); intervalContainer.add(interval); - TextField cron = new TextField("cron", new PropertyModel( - model, "cron")); + TextField cron = new TextField<>(ID_CRON, new PropertyModel( + model, TaskAddDto.F_CRON)); cron.add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); // if (recurringCheck.getObject() && !boundCheck.getObject()) { // cron.setRequired(true); // } cronContainer.add(cron); - Label cronHelp = new Label("cronHelp"); + Label cronHelp = new Label(ID_CRON_HELP); cronHelp.add(new InfoTooltipBehavior()); cronContainer.add(cronHelp); - final DateTimeField notStartBefore = new DateTimeField("notStartBeforeField", - new PropertyModel(model, "notStartBefore")) { + final DateTimeField notStartBefore = new DateTimeField(ID_NO_START_BEFORE_FIELD, + new PropertyModel(model, TaskAddDto.F_NOT_START_BEFORE)) { @Override protected DateTextField newDateTextField(String id, PropertyModel dateFieldModel) { return DateTextField.forDatePattern(id, dateFieldModel, "dd/MMM/yyyy"); // todo i18n @@ -277,8 +345,8 @@ protected DateTextField newDateTextField(String id, PropertyModel dateFieldModel notStartBefore.setOutputMarkupId(true); mainForm.add(notStartBefore); - final DateTimeField notStartAfter = new DateTimeField("notStartAfterField", new PropertyModel( - model, "notStartAfter")) { + final DateTimeField notStartAfter = new DateTimeField(ID_NO_START_AFTER_FIELD, new PropertyModel( + model, TaskAddDto.F_NOT_START_AFTER)) { @Override protected DateTextField newDateTextField(String id, PropertyModel dateFieldModel) { return DateTextField.forDatePattern(id, dateFieldModel, "dd/MMM/yyyy"); // todo i18n @@ -293,15 +361,15 @@ protected DateTextField newDateTextField(String id, PropertyModel dateFieldModel } private void initAdvanced(Form mainForm) { - CheckBox runUntilNodeDown = new CheckBox("runUntilNodeDown", new PropertyModel(model, - "runUntilNodeDown")); + CheckBox runUntilNodeDown = new CheckBox(ID_RUN_UNTIL_NODW_DOWN, new PropertyModel(model, + TaskAddDto.F_RUN_UNTIL_NODW_DOWN)); mainForm.add(runUntilNodeDown); - final IModel createSuspendedCheck = new PropertyModel(model, "suspendedState"); - CheckBox createSuspended = new CheckBox("createSuspended", createSuspendedCheck); + final IModel createSuspendedCheck = new PropertyModel<>(model, TaskAddDto.F_SUSPENDED_STATE); + CheckBox createSuspended = new CheckBox(ID_CREATE_SUSPENDED, createSuspendedCheck); mainForm.add(createSuspended); - DropDownChoice threadStop = new DropDownChoice("threadStop", new Model() { + DropDownChoice threadStop = new DropDownChoice(ID_THREAD_STOP, new Model() { @Override public ThreadStopActionType getObject() { @@ -326,14 +394,14 @@ public void setObject(ThreadStopActionType object) { mainForm.add(new TsaValidator(runUntilNodeDown, threadStop)); - DropDownChoice misfire = new DropDownChoice("misfireAction", new PropertyModel( - model, "misfireAction"), WebMiscUtil.createReadonlyModelFromEnum(MisfireActionType.class), + DropDownChoice misfire = new DropDownChoice(ID_MISFIRE_ACTION, new PropertyModel( + model, TaskAddDto.F_MISFIRE_ACTION), WebMiscUtil.createReadonlyModelFromEnum(MisfireActionType.class), new EnumChoiceRenderer(PageTaskAdd.this)); mainForm.add(misfire); } private void initButtons(final Form mainForm) { - AjaxSubmitButton saveButton = new AjaxSubmitButton("saveButton", + AjaxSubmitButton saveButton = new AjaxSubmitButton(ID_BUTTON_SAVE, createStringResource("PageBase.button.save")) { @Override @@ -348,7 +416,7 @@ protected void onError(AjaxRequestTarget target, Form form) { }; mainForm.add(saveButton); - AjaxButton backButton = new AjaxButton("backButton", + AjaxButton backButton = new AjaxButton(ID_BUTTON_BACK, createStringResource("PageBase.button.back")) { @Override @@ -360,7 +428,7 @@ public void onClick(AjaxRequestTarget target) { } private List createCategoryList() { - List categories = new ArrayList(); + List categories = new ArrayList<>(); // todo change to something better and add i18n // TaskManager manager = getTaskManager(); @@ -381,6 +449,16 @@ private List createCategoryList() { return categories; } + private List createShadowKindTypeList(){ + List kindList = new ArrayList<>(); + + kindList.add(ShadowKindType.ACCOUNT); + kindList.add(ShadowKindType.ENTITLEMENT); + kindList.add(ShadowKindType.GENERIC); + + return kindList; + } + private List createResourceList() { OperationResult result = new OperationResult(OPERATION_LOAD_RESOURCES); Task task = createSimpleTask(OPERATION_LOAD_RESOURCES); @@ -505,6 +583,28 @@ private TaskType createTask(TaskAddDto dto) throws SchemaException { dryRun.setRealValue(true); } + if(dto.getKind() != null){ + PrismObject prismTask = task.asPrismObject(); + ItemPath path = new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_KIND); + PrismProperty kind = prismTask.findOrCreateProperty(path); + + SchemaRegistry registry = getPrismContext().getSchemaRegistry(); + PrismPropertyDefinition def = registry.findPropertyDefinitionByElementName(SchemaConstants.MODEL_EXTENSION_KIND); + kind.setDefinition(def); + kind.setRealValue(dto.getKind()); + } + + if(dto.getIntent() != null && StringUtils.isNotEmpty(dto.getIntent())){ + PrismObject prismTask = task.asPrismObject(); + ItemPath path = new ItemPath(TaskType.F_EXTENSION, SchemaConstants.MODEL_EXTENSION_INTENT); + PrismProperty intent = prismTask.findOrCreateProperty(path); + + SchemaRegistry registry = getPrismContext().getSchemaRegistry(); + PrismPropertyDefinition def = registry.findPropertyDefinitionByElementName(SchemaConstants.MODEL_EXTENSION_INTENT); + intent.setDefinition(def); + intent.setRealValue(dto.getIntent()); + } + return task; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskAdd.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskAdd.properties index 2fdba8fd07e..d7088aee6c7 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskAdd.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskAdd.properties @@ -16,9 +16,11 @@ page.title=New task pageTask.title.edit=Details for '{0}' pageTask.type=Type: -pageTask.objectRef=Object reference +pageTask.objectRef=Resource reference pageTask.browse=Browse pageTask.name=Task name +pageTask.kind=Kind +pageTask.intent=Intent pageTask.scheduleTitle=Scheduling pageTask.recurring=Recurring task pageTask.bound=Tightly bound (use if recurring task runs often) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.html index 2a694e00495..49c65c01a75 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.html @@ -59,6 +59,15 @@

+ + + + + +

diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.java index b85f990b476..c6038532b12 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.java @@ -61,6 +61,7 @@ import com.evolveum.midpoint.web.util.WebMiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.apache.commons.lang.StringUtils; import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; @@ -110,6 +111,8 @@ public class PageTaskEdit extends PageAdminTasks { private static final String ID_HANDLER_URI_LIST = "handlerUriList"; private static final String ID_HANDLER_URI = "handlerUri"; private static final String ID_RESOURCE_REF = "resourceRef"; + private static final String ID_KIND = "kind"; + private static final String ID_INTENT = "intent"; private static final String ID_MODEL_OPERATION_STATUS_LABEL = "modelOperationStatusLabel"; private static final String ID_MODEL_OPERATION_STATUS_PANEL = "modelOperationStatusPanel"; private static final String ID_SUBTASKS_LABEL = "subtasksLabel"; @@ -442,6 +445,7 @@ public String getIdValue(TaskAddResourcesDto object, int index) { }); resource.setOutputMarkupId(true); resource.add(new VisibleEnableBehaviour() { + @Override public boolean isEnabled() { if(!edit) @@ -456,6 +460,56 @@ public boolean isEnabled() { }); mainForm.add(resource); + final DropDownChoice kind = new DropDownChoice(ID_KIND, + new PropertyModel(model, TaskDto.F_KIND), + new AbstractReadOnlyModel>() { + + @Override + public List getObject() { + return createShadowKindTypeList(); + } + }, new IChoiceRenderer() { + + @Override + public Object getDisplayValue(ShadowKindType object) { + return object.value(); + } + + @Override + public String getIdValue(ShadowKindType object, int index) { + return Integer.toString(index); + } + }); + kind.setOutputMarkupId(true); + kind.setNullValid(true); + kind.add(new VisibleEnableBehaviour(){ + + @Override + public boolean isEnabled() { + if(!edit) + return false; + + TaskDto dto = model.getObject(); + return TaskCategory.RECONCILIATION.equals(dto.getCategory()); + } + }); + mainForm.add(kind); + + final TextField intent = new TextField<>(ID_INTENT, new PropertyModel(model, TaskDto.F_INTENT)); + mainForm.add(intent); + intent.setOutputMarkupId(true); + intent.add(new VisibleEnableBehaviour(){ + + @Override + public boolean isEnabled() { + if(!edit) + return false; + + TaskDto dto = model.getObject(); + return TaskCategory.RECONCILIATION.equals(dto.getCategory()); + } + }); + Label node = new Label("node", new AbstractReadOnlyModel() { @Override public String getObject() { @@ -469,6 +523,16 @@ public String getObject() { mainForm.add(node); } + private List createShadowKindTypeList(){ + List kindList = new ArrayList<>(); + + kindList.add(ShadowKindType.ACCOUNT); + kindList.add(ShadowKindType.ENTITLEMENT); + kindList.add(ShadowKindType.GENERIC); + + return kindList; + } + private void initSchedule(Form mainForm) { //todo probably can be removed, visibility can be updated in children (already components) [lazyman] final WebMarkupContainer container = new WebMarkupContainer("container"); @@ -899,8 +963,8 @@ private Task updateTask(TaskDto dto, Task existingTask) throws SchemaException { // } existingTask.setThreadStopAction(tsa); + SchemaRegistry registry = getPrismContext().getSchemaRegistry(); if (dto.isDryRun()) { - SchemaRegistry registry = getPrismContext().getSchemaRegistry(); PrismPropertyDefinition def = registry.findPropertyDefinitionByElementName(SchemaConstants.MODEL_EXTENSION_DRY_RUN); PrismProperty dryRun = new PrismProperty(SchemaConstants.MODEL_EXTENSION_DRY_RUN); dryRun.setDefinition(def); @@ -913,6 +977,37 @@ private Task updateTask(TaskDto dto, Task existingTask) throws SchemaException { existingTask.deleteExtensionProperty(dryRun); } } + + if(dto.getKind() != null){ + PrismPropertyDefinition def = registry.findPropertyDefinitionByElementName(SchemaConstants.MODEL_EXTENSION_KIND); + PrismProperty kind = new PrismProperty(SchemaConstants.MODEL_EXTENSION_KIND); + kind.setDefinition(def); + kind.setRealValue(dto.getKind()); + + existingTask.addExtensionProperty(kind); + } else { + PrismProperty kind = existingTask.getExtensionProperty(SchemaConstants.MODEL_EXTENSION_KIND); + + if(kind != null){ + existingTask.deleteExtensionProperty(kind); + } + } + + if(dto.getIntent() != null && StringUtils.isNotEmpty(dto.getIntent())){ + PrismPropertyDefinition def = registry.findPropertyDefinitionByElementName(SchemaConstants.MODEL_EXTENSION_INTENT); + PrismProperty intent = new PrismProperty(SchemaConstants.MODEL_EXTENSION_INTENT); + intent.setDefinition(def); + intent.setRealValue(dto.getIntent()); + + existingTask.addExtensionProperty(intent); + } else { + PrismProperty intent = existingTask.getExtensionProperty(SchemaConstants.MODEL_EXTENSION_INTENT); + + if(intent != null){ + existingTask.deleteExtensionProperty(intent); + } + } + return existingTask; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.properties index edb81e76f4b..8db8d695086 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/PageTaskEdit.properties @@ -32,6 +32,8 @@ pageTaskEdit.parent=Parent task pageTaskEdit.handlerUri=Handler URI pageTaskEdit.execution=Execution status pageTaskEdit.objectRef=Resource reference +pageTaskEdit.kind=Kind +pageTaskEdit.intent=Intent pageTaskEdit.suspendReq=For editing is necessary to suspend the task pageTaskEdit.scheduleTitle=Scheduling @@ -79,3 +81,4 @@ pageTaskEdit.dryRun=Dry run runUntilNodeDown.error1=Compatible data for 'Thread stop action' are: Close, Suspend runUntilNodeDown.error2=Compatible data for 'Thread stop action' are: Restart, Reschedule +nullValid=Choose one diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/dto/TaskAddDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/dto/TaskAddDto.java index 365d665222c..316550a9aa9 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/dto/TaskAddDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/dto/TaskAddDto.java @@ -20,6 +20,7 @@ import java.util.Date; import com.evolveum.midpoint.xml.ns._public.common.common_3.MisfireActionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ThreadStopActionType; /** @@ -28,6 +29,21 @@ public class TaskAddDto implements Serializable { public static final String F_DRY_RUN = "dryRun"; + public static final String F_KIND = "kind"; + public static final String F_INTENT = "intent"; + public static final String F_RESOURCE = "resource"; + public static final String F_CATEGORY = "category"; + public static final String F_NAME = "name"; + public static final String F_RECURRING = "reccuring"; + public static final String F_BOUND = "bound"; + public static final String F_INTERVAL = "interval"; + public static final String F_CRON = "cron"; + public static final String F_NOT_START_BEFORE = "notStartBefore"; + public static final String F_NOT_START_AFTER = "notStartAfter"; + public static final String F_RUN_UNTIL_NODW_DOWN = "runUntilNodeDown"; + public static final String F_SUSPENDED_STATE = "suspendedState"; + public static final String F_THREAD_STOP = "threadStop"; + public static final String F_MISFIRE_ACTION = "misfireAction"; private String category; private TaskAddResourcesDto resource; @@ -49,6 +65,8 @@ public class TaskAddDto implements Serializable { private MisfireActionType misfireAction = MisfireActionType.EXECUTE_IMMEDIATELY; private boolean dryRun; + private ShadowKindType kind; + private String intent; public String getCategory() { return category; @@ -161,4 +179,20 @@ public boolean isDryRun() { public void setDryRun(boolean dryRun) { this.dryRun = dryRun; } + + public ShadowKindType getKind() { + return kind; + } + + public void setKind(ShadowKindType kind) { + this.kind = kind; + } + + public String getIntent() { + return intent; + } + + public void setIntent(String intent) { + this.intent = intent; + } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/dto/TaskDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/dto/TaskDto.java index 9c55d8e3a86..e16a2b106e3 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/dto/TaskDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/server/dto/TaskDto.java @@ -87,6 +87,8 @@ public class TaskDto extends Selectable { public static final String F_TASK_OPERATION_RESULT = "taskOperationResult"; public static final String F_PROGRESS_DESCRIPTION = "progressDescription"; public static final String F_DRY_RUN = "dryRun"; + public static final String F_KIND = "kind"; + public static final String F_INTENT = "intent"; public static final String F_RESOURCE_REFERENCE = "resourceRef"; private List handlerUriList; @@ -128,6 +130,8 @@ public class TaskDto extends Selectable { private List workflowHistory; private boolean dryRun; + private ShadowKindType kind; + private String intent; private TaskType taskType; @@ -156,7 +160,8 @@ public TaskDto(TaskType taskType, ModelService modelService, TaskService taskSer fillInWorkflowAttributes(taskType); thisOpResult.computeStatusIfUnknown(); - fillDryRun(taskType); + //dryRun, intent and kind + fillFromExtension(taskType); } private void fillInResourceReference(TaskType task, TaskManager manager, OperationResult result, ModelService service){ @@ -167,7 +172,7 @@ private void fillInResourceReference(TaskType task, TaskManager manager, Operati } } - private void fillDryRun(TaskType taskType) { + private void fillFromExtension(TaskType taskType) { PrismObject task = taskType.asPrismObject(); if (task.getExtension() == null) { dryRun = false; @@ -177,10 +182,19 @@ private void fillDryRun(TaskType taskType) { PrismProperty item = task.getExtension().findProperty(SchemaConstants.MODEL_EXTENSION_DRY_RUN); if (item == null || item.getRealValue() == null) { dryRun = false; - return; + } else { + dryRun = item.getRealValue(); } - dryRun = item.getRealValue(); + PrismProperty kindItem = task.getExtension().findProperty(SchemaConstants.MODEL_EXTENSION_KIND); + if(kindItem != null && kindItem.getRealValue() != null){ + kind = kindItem.getRealValue(); + } + + PrismProperty intentItem = task.getExtension().findProperty(SchemaConstants.MODEL_EXTENSION_INTENT); + if(intentItem != null && intentItem.getRealValue() != null){ + intent = intentItem.getRealValue(); + } } private void fillInTimestamps(TaskType taskType) { @@ -709,4 +723,28 @@ public TaskAddResourcesDto getResource() { public void setResource(TaskAddResourcesDto resource) { this.resourceRef = resource; } + + public String getIntent() { + return intent; + } + + public void setIntent(String intent) { + this.intent = intent; + } + + public TaskType getTaskType() { + return taskType; + } + + public void setTaskType(TaskType taskType) { + this.taskType = taskType; + } + + public ShadowKindType getKind() { + return kind; + } + + public void setKind(ShadowKindType kind) { + this.kind = kind; + } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUser.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUser.java index bd605836697..19dfe28a33f 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUser.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageUser.java @@ -1260,7 +1260,6 @@ private void savePerformed(AjaxRequestTarget target) { ExecuteChangeOptionsDto executeOptions = executeOptionsModel.getObject(); ModelExecuteOptions options = executeOptions.createOptions(); LOGGER.debug("Using options {}.", new Object[]{executeOptions}); - // try { try { reviveModels(); diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java index a667d93a5a7..42f46d1b5b7 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/constants/SchemaConstants.java @@ -163,6 +163,8 @@ public abstract class SchemaConstants { public static final String NS_MODEL_EXTENSION = NS_MODEL + "/extension-3"; public static final QName MODEL_EXTENSION_FRESHENESS_INTERVAL_PROPERTY_NAME = new QName(NS_MODEL_EXTENSION, "freshnessInterval"); public static final QName MODEL_EXTENSION_DRY_RUN = new QName(NS_MODEL_EXTENSION, "dryRun"); + public static final QName MODEL_EXTENSION_KIND = new QName(NS_MODEL_EXTENSION, "kind"); + public static final QName MODEL_EXTENSION_INTENT = new QName(NS_MODEL_EXTENSION, "intent"); public static final QName MODEL_EXTENSION_LAST_SCAN_TIMESTAMP_PROPERTY_NAME = new QName(NS_MODEL_EXTENSION, "lastScanTimestamp"); public static final String NS_MODEL_DISABLE_REASON = NS_MODEL + "/disableReason"; From 8bac2c31a14d4d2c1555c25b08fdb40794c4f5d6 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Thu, 24 Jul 2014 17:51:52 +0200 Subject: [PATCH 27/51] fixing incorrect behaviour while handling not found error. --- .../midpoint/model/impl/controller/ModelController.java | 6 +++++- .../java/com/evolveum/midpoint/model/impl/util/Utils.java | 4 +++- .../midpoint/repo/sql/SqlRepositoryServiceImpl.java | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) 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 af7d50ce2e5..1dd55f012f9 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 @@ -293,7 +293,11 @@ public PrismObject getObject(Class clazz, String oi ModelUtils.recordFatalError(result, e); throw e; } catch (ObjectNotFoundException e) { - ModelUtils.recordFatalError(result, e); + if (GetOperationOptions.isAllowNotFound(rootOptions)){ + result.getLastSubresult().setStatus(OperationResultStatus.HANDLED_ERROR); + } else { + ModelUtils.recordFatalError(result, e); + } throw e; } catch (CommunicationException e) { ModelUtils.recordFatalError(result, e); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java index ca06280b947..4d0cbab6d70 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java @@ -52,6 +52,8 @@ import com.evolveum.midpoint.prism.query.QueryJaxbConvertor; import com.evolveum.midpoint.provisioning.api.ProvisioningService; import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.constants.ExpressionConstants; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; @@ -468,7 +470,7 @@ public static PrismObject getSystemConfiguration(Reposi PrismObject systemConfiguration = null; try { systemConfiguration = repositoryService.getObject(SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), - null, result); + SelectorOptions.createCollection(GetOperationOptions.createAllowNotFound()), result); } catch (ObjectNotFoundException e) { // just go on ... we will return and continue // This is needed e.g. to set up new system configuration is the old one gets deleted diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlRepositoryServiceImpl.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlRepositoryServiceImpl.java index 3a46eed00b6..96ae257e639 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlRepositoryServiceImpl.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlRepositoryServiceImpl.java @@ -238,7 +238,8 @@ private PrismObject getObjectAttempt(Class type, St session.getTransaction().commit(); } catch (ObjectNotFoundException ex) { - rollbackTransaction(session, ex, result, true); + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + rollbackTransaction(session, ex, result, !GetOperationOptions.isAllowNotFound(rootOptions)); throw ex; } catch (SchemaException ex) { rollbackTransaction(session, ex, "Schema error while getting object with oid: " From a9fdbeeb61a98d68cea434b5b07172a5f720194c Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Fri, 25 Jul 2014 09:56:02 +0200 Subject: [PATCH 28/51] Refctoring: splitting dependencies out of projector class. --- .../lens/projector/DependencyProcessor.java | 419 ++++++++++++++++++ .../model/impl/lens/projector/Projector.java | 366 +-------------- 2 files changed, 428 insertions(+), 357 deletions(-) create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java new file mode 100644 index 00000000000..4b27c99ed17 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2010-2014 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.lens.projector; + +import static com.evolveum.midpoint.common.InternalsConfig.consistencyChecks; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import javax.xml.datatype.XMLGregorianCalendar; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.evolveum.midpoint.common.Clock; +import com.evolveum.midpoint.common.refinery.ResourceShadowDiscriminator; +import com.evolveum.midpoint.model.api.PolicyViolationException; +import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; +import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.model.impl.lens.LensFocusContext; +import com.evolveum.midpoint.model.impl.lens.LensObjectDeltaOperation; +import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; +import com.evolveum.midpoint.model.impl.lens.LensUtil; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ResourceTypeUtil; +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.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectTypeDependencyStrictnessType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectTypeDependencyType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; + +/** + * @author Radovan Semancik + * + */ +@Component +public class DependencyProcessor { + + private static final Trace LOGGER = TraceManager.getTrace(DependencyProcessor.class); + + public void resetWaves(LensContext context) throws PolicyViolationException { + } + + public void sortProjectionsToWaves(LensContext context) throws PolicyViolationException { + // Create a snapshot of the projection collection at the beginning of computation. + // The collection may be changed during computation (projections may be added). We do not want to process + // these added projections. They are already processed inside the computation. + // This also avoids ConcurrentModificationException + LensProjectionContext[] projectionArray = context.getProjectionContexts().toArray(new LensProjectionContext[0]); + + // Reset incomplete flag for those contexts that are not yet computed + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + if (projectionContext.getWave() < 0) { + projectionContext.setWaveIncomplete(true); + } + } + + for (LensProjectionContext projectionContext: projectionArray) { + determineProjectionWave(context, projectionContext, null, null); + projectionContext.setWaveIncomplete(false); + } + + if (LOGGER.isTraceEnabled()) { + StringBuilder sb = new StringBuilder(); + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + sb.append("\n"); + sb.append(projectionContext.getResourceShadowDiscriminator()); + sb.append(": "); + sb.append(projectionContext.getWave()); + } + LOGGER.trace("Projections sorted to waves (projection wave {}, execution wave {}):{}", + new Object[]{context.getProjectionWave(), context.getExecutionWave(), sb.toString()}); + } + } + + public int computeMaxWaves(LensContext context) { + return context.getMaxWave() + 2; + } + + // TODO: check for circular dependencies + private LensProjectionContext determineProjectionWave(LensContext context, + LensProjectionContext projectionContext, ResourceObjectTypeDependencyType inDependency, List depPath) throws PolicyViolationException { + if (!projectionContext.isWaveIncomplete()) { + // This was already processed + return projectionContext; + } + if (projectionContext.isDelete()) { + // Ignore dependencies if we are being removed + projectionContext.setWave(0); + return projectionContext; + } + if (depPath == null) { + depPath = new ArrayList(); + } + int determinedWave = 0; + int determinedOrder = 0; + for (ResourceObjectTypeDependencyType outDependency: projectionContext.getDependencies()) { +// if (LOGGER.isTraceEnabled()) { +// LOGGER.trace("DEP: {}", outDependency); +// } + if (inDependency != null && isHigerOrder(outDependency, inDependency)) { + // There is incomming dependency. Deal only with dependencies of this order and lower + // otherwise we can end up in endless loop even for legal dependencies. + continue; + } + checkForCircular(depPath, outDependency); + depPath.add(outDependency); + ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(outDependency, + projectionContext.getResource().getOid(), projectionContext.getKind()); + LensProjectionContext dependencyProjectionContext = findDependencyContext(context, projectionContext, outDependency); +// if (LOGGER.isTraceEnabled()) { +// LOGGER.trace("DEP: {} -> {}", refDiscr, dependencyProjectionContext); +// } + if (dependencyProjectionContext == null) { + ResourceObjectTypeDependencyStrictnessType outDependencyStrictness = ResourceTypeUtil.getDependencyStrictness(outDependency); + if (outDependencyStrictness == ResourceObjectTypeDependencyStrictnessType.STRICT) { + throw new PolicyViolationException("Unsatisfied strict dependency of account "+projectionContext.getResourceShadowDiscriminator()+ + " dependent on "+refDiscr+": Account not provisioned"); + } else if (outDependencyStrictness == ResourceObjectTypeDependencyStrictnessType.LAX) { + // independent object not in the context, just ignore it + LOGGER.debug("Unsatisfied lax dependency of account "+projectionContext.getResourceShadowDiscriminator()+ + " dependent on "+refDiscr+"; dependency skipped"); + } else if (outDependencyStrictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) { + // independent object not in the context, just ignore it + LOGGER.debug("Unsatisfied relaxed dependency of account "+projectionContext.getResourceShadowDiscriminator()+ + " dependent on "+refDiscr+"; dependency skipped"); + } else { + throw new IllegalArgumentException("Unknown dependency strictness "+outDependency.getStrictness()+" in "+refDiscr); + } + } else { + dependencyProjectionContext = determineProjectionWave(context, dependencyProjectionContext, outDependency, depPath); + if (dependencyProjectionContext.getWave() + 1 > determinedWave) { + determinedWave = dependencyProjectionContext.getWave() + 1; + if (outDependency.getOrder() == null) { + determinedOrder = 0; + } else { + determinedOrder = outDependency.getOrder(); + } + } + } + depPath.remove(outDependency); + } + LensProjectionContext resultAccountContext = projectionContext; + if (projectionContext.getWave() >=0 && projectionContext.getWave() != determinedWave) { + // Wave for this context was set during the run of this method (it was not set when we + // started, we checked at the beginning). Therefore this context must have been visited again. + // therefore there is a circular dependency. Therefore we need to create another context to split it. + resultAccountContext = createAnotherContext(context, projectionContext, determinedOrder); + } +// LOGGER.trace("Wave for {}: {}", resultAccountContext.getResourceAccountType(), wave); + resultAccountContext.setWave(determinedWave); + return resultAccountContext; + } + + private void checkForCircular(List depPath, + ResourceObjectTypeDependencyType outDependency) throws PolicyViolationException { + for (ResourceObjectTypeDependencyType pathElement: depPath) { + if (pathElement.equals(outDependency)) { + StringBuilder sb = new StringBuilder(); + Iterator iterator = depPath.iterator(); + while (iterator.hasNext()) { + ResourceObjectTypeDependencyType el = iterator.next(); + sb.append(el.getResourceRef().getOid()); + if (iterator.hasNext()) { + sb.append("->"); + } + } + throw new PolicyViolationException("Circular dependency, path: "+sb.toString()); + } + } + } + + private boolean isHigerOrder(ResourceObjectTypeDependencyType a, + ResourceObjectTypeDependencyType b) { + Integer ao = a.getOrder(); + Integer bo = b.getOrder(); + if (ao == null) { + ao = 0; + } + if (bo == null) { + bo = 0; + } + return ao > bo; + } + + /** + * Find context that has the closest order to the dependency. + */ + private LensProjectionContext findDependencyContext( + LensContext context, LensProjectionContext projContext, ResourceObjectTypeDependencyType dependency){ + ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(dependency, + projContext.getResource().getOid(), projContext.getKind()); + LensProjectionContext selected = null; + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + if (!projectionContext.compareResourceShadowDiscriminator(refDiscr, false)) { + continue; + } + int ctxOrder = projectionContext.getResourceShadowDiscriminator().getOrder(); + if (ctxOrder > refDiscr.getOrder()) { + continue; + } + if (selected == null) { + selected = projectionContext; + } else { + if (ctxOrder > selected.getResourceShadowDiscriminator().getOrder()) { + selected = projectionContext; + } + } + } + return selected; + } + + private LensProjectionContext createAnotherContext(LensContext context, + LensProjectionContext origProjectionContext, int order) throws PolicyViolationException { + ResourceShadowDiscriminator origDiscr = origProjectionContext.getResourceShadowDiscriminator(); + ResourceShadowDiscriminator discr = new ResourceShadowDiscriminator(origDiscr.getResourceOid(), origDiscr.getKind(), origDiscr.getIntent(), origDiscr.isThombstone()); + discr.setOrder(order); + LensProjectionContext otherCtx = context.createProjectionContext(discr); + otherCtx.setResource(origProjectionContext.getResource()); + // Force recon for the new context. This is a primitive way how to avoid phantom changes. + otherCtx.setDoReconciliation(true); + return otherCtx; + } + + /** + * Check that the dependencies are still satisfied. Also check for high-ordes vs low-order operation consistency + * and stuff like that. + */ + public boolean checkDependencies(LensContext context, + LensProjectionContext projContext) throws PolicyViolationException { + if (projContext.isDelete()) { + // It is OK if we depend on something that is not there if we are being removed ... for now + return true; + } + + if (projContext.getOid() == null || projContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD) { + // Check for lower-order contexts + LensProjectionContext lowerOrderContext = null; + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + if (projContext == projectionContext) { + continue; + } + if (projectionContext.compareResourceShadowDiscriminator(projContext.getResourceShadowDiscriminator(), false) && + projectionContext.getResourceShadowDiscriminator().getOrder() < projContext.getResourceShadowDiscriminator().getOrder()) { + if (projectionContext.getOid() != null) { + lowerOrderContext = projectionContext; + break; + } + } + } + if (lowerOrderContext != null) { + if (lowerOrderContext.getOid() != null) { + if (projContext.getOid() == null) { + projContext.setOid(lowerOrderContext.getOid()); + } + if (projContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD) { + // This context cannot be ADD. There is a lower-order context with an OID + // it means that the lower-order projection exists, we cannot add it twice + projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.KEEP); + } + } + if (lowerOrderContext.isDelete()) { + projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.DELETE); + } + } + } + + for (ResourceObjectTypeDependencyType dependency: projContext.getDependencies()) { + ResourceShadowDiscriminator refRat = new ResourceShadowDiscriminator(dependency, + projContext.getResource().getOid(), projContext.getKind()); + LOGGER.trace("LOOKING FOR {}", refRat); + LensProjectionContext dependencyAccountContext = context.findProjectionContext(refRat); + ResourceObjectTypeDependencyStrictnessType strictness = ResourceTypeUtil.getDependencyStrictness(dependency); + if (dependencyAccountContext == null) { + if (strictness == ResourceObjectTypeDependencyStrictnessType.STRICT) { + // This should not happen, it is checked before projection + throw new PolicyViolationException("Unsatisfied strict dependency of " + + projContext.getResourceShadowDiscriminator().toHumanReadableString() + + " dependent on " + refRat.toHumanReadableString() + ": No context in dependency check"); + } else if (strictness == ResourceObjectTypeDependencyStrictnessType.LAX) { + // independent object not in the context, just ignore it + LOGGER.trace("Unsatisfied lax dependency of account " + + projContext.getResourceShadowDiscriminator().toHumanReadableString() + + " dependent on " + refRat.toHumanReadableString() + "; dependency skipped"); + } else if (strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) { + // independent object not in the context, just ignore it + LOGGER.trace("Unsatisfied relaxed dependency of account " + + projContext.getResourceShadowDiscriminator().toHumanReadableString() + + " dependent on " + refRat.toHumanReadableString() + "; dependency skipped"); + } else { + throw new IllegalArgumentException("Unknown dependency strictness "+dependency.getStrictness()+" in "+refRat); + } + } else { + // We have the context of the object that we depend on. We need to check if it was provisioned. + if (strictness == ResourceObjectTypeDependencyStrictnessType.STRICT + || strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) { + if (wasProvisioned(dependencyAccountContext, context.getExecutionWave())) { + // everything OK + } else { + // We do not want to throw exception here. That will stop entire projection. + // Let's just mark the projection as broken and skip it. + LOGGER.warn("Unsatisfied dependency of account "+projContext.getResourceShadowDiscriminator()+ + " dependent on "+refRat+": Account not provisioned in dependency check (execution wave "+context.getExecutionWave()+", account wave "+projContext.getWave() + ", depenedency account wave "+dependencyAccountContext.getWave()+")"); + projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.BROKEN); + return false; + } + } else if (strictness == ResourceObjectTypeDependencyStrictnessType.LAX) { + // we don't care what happened, just go on + return true; + } else { + throw new IllegalArgumentException("Unknown dependency strictness "+dependency.getStrictness()+" in "+refRat); + } + } + } + return true; + } + + /** + * Finally checks for all the dependencies. Some dependencies cannot be checked during wave computations as + * we might not have all activation decisions yet. + */ + public void checkDependenciesFinal(LensContext context) throws PolicyViolationException { + + for (LensProjectionContext accountContext: context.getProjectionContexts()) { + checkDependencies(context, accountContext); + } + + for (LensProjectionContext accountContext: context.getProjectionContexts()) { + if (accountContext.isDelete() + || accountContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.UNLINK) { + // It is OK if we depend on something that is not there if we are being removed + // but we still need to check if others depends on me + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + if (projectionContext.isDelete() + || projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.UNLINK + || projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN + || projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) { + // If someone who is being deleted depends on us then it does not really matter + continue; + } + for (ResourceObjectTypeDependencyType dependency: projectionContext.getDependencies()) { + if (dependency.getResourceRef().getOid().equals(accountContext.getResource().getOid())) { + // Someone depends on us + if (ResourceTypeUtil.getDependencyStrictness(dependency) == ResourceObjectTypeDependencyStrictnessType.STRICT) { + throw new PolicyViolationException("Cannot remove "+accountContext.getHumanReadableName() + +" because "+projectionContext.getHumanReadableName()+" depends on it"); + } + } + } + } + + } + } + } + + private boolean wasProvisioned(LensProjectionContext accountContext, int executionWave) { + int accountWave = accountContext.getWave(); + if (accountWave >= executionWave) { + // This had no chance to be provisioned yet, so we assume it will be provisioned + return true; + } + if (accountContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN + || accountContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) { + return false; + } + PrismObject objectCurrent = accountContext.getObjectCurrent(); + if (objectCurrent != null && objectCurrent.asObjectable().getFailedOperationType() != null) { + // There is unfinished operation in the shadow. We cannot continue. + return false; + } + if (accountContext.isExists()) { + return true; + } + if (accountContext.isAdd()) { + List> executedDeltas = accountContext.getExecutedDeltas(); + if (executedDeltas == null || executedDeltas.isEmpty()) { + return false; + } + for (LensObjectDeltaOperation executedDelta: executedDeltas) { + OperationResult executionResult = executedDelta.getExecutionResult(); + if (executionResult == null || !executionResult.isSuccess()) { + return false; + } + } + return true; + } + return false; + } + + + +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java index ecac5490e77..7cc0e68c72d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java @@ -95,6 +95,9 @@ public class Projector { @Autowired(required = true) private ActivationProcessor activationProcessor; + @Autowired(required = true) + private DependencyProcessor dependencyProcessor; + @Autowired(required = true) private Clock clock; @@ -134,10 +137,10 @@ public void project(LensContext context, String activi context.setFresh(true); if (consistencyChecks) context.checkConsistence(); - sortProjectionsToWaves(context); + dependencyProcessor.sortProjectionsToWaves(context); // Let's do one extra wave with no accounts in it. This time we expect to get the results of the execution to the user // via inbound, e.g. identifiers generated by the resource, DNs and similar things. Hence the +2 instead of +1 - int maxWaves = computeMaxWaves(context); + int maxWaves = dependencyProcessor.computeMaxWaves(context); // Note that the number of waves may be recomputed as new accounts appear in the context (usually after assignment step). // Start the waves .... @@ -154,8 +157,8 @@ public void project(LensContext context, String activi context.recomputeFocus(); if (consistencyChecks) context.checkConsistence(); - sortProjectionsToWaves(context); - maxWaves = computeMaxWaves(context); + dependencyProcessor.sortProjectionsToWaves(context); + maxWaves = dependencyProcessor.computeMaxWaves(context); LOGGER.trace("Continuing wave {}, maxWaves={}", context.getProjectionWave(), maxWaves); LensUtil.traceContext(LOGGER, activityDescription,"focus processing", false, context, false); @@ -204,7 +207,7 @@ public void project(LensContext context, String activi continue; } - if (!checkDependencies(context, projectionContext)) { + if (!dependencyProcessor.checkDependencies(context, projectionContext)) { continue; } @@ -248,7 +251,7 @@ public void project(LensContext context, String activi // We can do this only when computation of all the waves is finished. Before that we do not know // activation of every account and therefore cannot decide what is OK and what is not - checkDependenciesFinal(context); + dependencyProcessor.checkDependenciesFinal(context); if (consistencyChecks) context.checkConsistence(); @@ -324,355 +327,4 @@ private void recordSuccess(XMLGregorianCalendar projectoStartTimestampCal, Opera } } - public void resetWaves(LensContext context) throws PolicyViolationException { - } - - public void sortProjectionsToWaves(LensContext context) throws PolicyViolationException { - // Create a snapshot of the projection collection at the beginning of computation. - // The collection may be changed during computation (projections may be added). We do not want to process - // these added projections. They are already processed inside the computation. - // This also avoids ConcurrentModificationException - LensProjectionContext[] projectionArray = context.getProjectionContexts().toArray(new LensProjectionContext[0]); - - // Reset incomplete flag for those contexts that are not yet computed - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - if (projectionContext.getWave() < 0) { - projectionContext.setWaveIncomplete(true); - } - } - - for (LensProjectionContext projectionContext: projectionArray) { - determineProjectionWave(context, projectionContext, null, null); - projectionContext.setWaveIncomplete(false); - } - - if (LOGGER.isTraceEnabled()) { - StringBuilder sb = new StringBuilder(); - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - sb.append("\n"); - sb.append(projectionContext.getResourceShadowDiscriminator()); - sb.append(": "); - sb.append(projectionContext.getWave()); - } - LOGGER.trace("Projections sorted to waves (projection wave {}, execution wave {}):{}", - new Object[]{context.getProjectionWave(), context.getExecutionWave(), sb.toString()}); - } - } - - public int computeMaxWaves(LensContext context) { - return context.getMaxWave() + 2; - } - - // TODO: check for circular dependencies - private LensProjectionContext determineProjectionWave(LensContext context, - LensProjectionContext projectionContext, ResourceObjectTypeDependencyType inDependency, List depPath) throws PolicyViolationException { - if (!projectionContext.isWaveIncomplete()) { - // This was already processed - return projectionContext; - } - if (projectionContext.isDelete()) { - // Ignore dependencies if we are being removed - projectionContext.setWave(0); - return projectionContext; - } - if (depPath == null) { - depPath = new ArrayList(); - } - int determinedWave = 0; - int determinedOrder = 0; - for (ResourceObjectTypeDependencyType outDependency: projectionContext.getDependencies()) { -// if (LOGGER.isTraceEnabled()) { -// LOGGER.trace("DEP: {}", outDependency); -// } - if (inDependency != null && isHigerOrder(outDependency, inDependency)) { - // There is incomming dependency. Deal only with dependencies of this order and lower - // otherwise we can end up in endless loop even for legal dependencies. - continue; - } - checkForCircular(depPath, outDependency); - depPath.add(outDependency); - ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(outDependency, - projectionContext.getResource().getOid(), projectionContext.getKind()); - LensProjectionContext dependencyProjectionContext = findDependencyContext(context, projectionContext, outDependency); -// if (LOGGER.isTraceEnabled()) { -// LOGGER.trace("DEP: {} -> {}", refDiscr, dependencyProjectionContext); -// } - if (dependencyProjectionContext == null) { - ResourceObjectTypeDependencyStrictnessType outDependencyStrictness = ResourceTypeUtil.getDependencyStrictness(outDependency); - if (outDependencyStrictness == ResourceObjectTypeDependencyStrictnessType.STRICT) { - throw new PolicyViolationException("Unsatisfied strict dependency of account "+projectionContext.getResourceShadowDiscriminator()+ - " dependent on "+refDiscr+": Account not provisioned"); - } else if (outDependencyStrictness == ResourceObjectTypeDependencyStrictnessType.LAX) { - // independent object not in the context, just ignore it - LOGGER.debug("Unsatisfied lax dependency of account "+projectionContext.getResourceShadowDiscriminator()+ - " dependent on "+refDiscr+"; dependency skipped"); - } else if (outDependencyStrictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) { - // independent object not in the context, just ignore it - LOGGER.debug("Unsatisfied relaxed dependency of account "+projectionContext.getResourceShadowDiscriminator()+ - " dependent on "+refDiscr+"; dependency skipped"); - } else { - throw new IllegalArgumentException("Unknown dependency strictness "+outDependency.getStrictness()+" in "+refDiscr); - } - } else { - dependencyProjectionContext = determineProjectionWave(context, dependencyProjectionContext, outDependency, depPath); - if (dependencyProjectionContext.getWave() + 1 > determinedWave) { - determinedWave = dependencyProjectionContext.getWave() + 1; - if (outDependency.getOrder() == null) { - determinedOrder = 0; - } else { - determinedOrder = outDependency.getOrder(); - } - } - } - depPath.remove(outDependency); - } - LensProjectionContext resultAccountContext = projectionContext; - if (projectionContext.getWave() >=0 && projectionContext.getWave() != determinedWave) { - // Wave for this context was set during the run of this method (it was not set when we - // started, we checked at the beginning). Therefore this context must have been visited again. - // therefore there is a circular dependency. Therefore we need to create another context to split it. - resultAccountContext = createAnotherContext(context, projectionContext, determinedOrder); - } -// LOGGER.trace("Wave for {}: {}", resultAccountContext.getResourceAccountType(), wave); - resultAccountContext.setWave(determinedWave); - return resultAccountContext; - } - - private void checkForCircular(List depPath, - ResourceObjectTypeDependencyType outDependency) throws PolicyViolationException { - for (ResourceObjectTypeDependencyType pathElement: depPath) { - if (pathElement.equals(outDependency)) { - StringBuilder sb = new StringBuilder(); - Iterator iterator = depPath.iterator(); - while (iterator.hasNext()) { - ResourceObjectTypeDependencyType el = iterator.next(); - sb.append(el.getResourceRef().getOid()); - if (iterator.hasNext()) { - sb.append("->"); - } - } - throw new PolicyViolationException("Circular dependency, path: "+sb.toString()); - } - } - } - - private boolean isHigerOrder(ResourceObjectTypeDependencyType a, - ResourceObjectTypeDependencyType b) { - Integer ao = a.getOrder(); - Integer bo = b.getOrder(); - if (ao == null) { - ao = 0; - } - if (bo == null) { - bo = 0; - } - return ao > bo; - } - - /** - * Find context that has the closest order to the dependency. - */ - private LensProjectionContext findDependencyContext( - LensContext context, LensProjectionContext projContext, ResourceObjectTypeDependencyType dependency){ - ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(dependency, - projContext.getResource().getOid(), projContext.getKind()); - LensProjectionContext selected = null; - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - if (!projectionContext.compareResourceShadowDiscriminator(refDiscr, false)) { - continue; - } - int ctxOrder = projectionContext.getResourceShadowDiscriminator().getOrder(); - if (ctxOrder > refDiscr.getOrder()) { - continue; - } - if (selected == null) { - selected = projectionContext; - } else { - if (ctxOrder > selected.getResourceShadowDiscriminator().getOrder()) { - selected = projectionContext; - } - } - } - return selected; - } - - private LensProjectionContext createAnotherContext(LensContext context, - LensProjectionContext origProjectionContext, int order) throws PolicyViolationException { - ResourceShadowDiscriminator origDiscr = origProjectionContext.getResourceShadowDiscriminator(); - ResourceShadowDiscriminator discr = new ResourceShadowDiscriminator(origDiscr.getResourceOid(), origDiscr.getKind(), origDiscr.getIntent(), origDiscr.isThombstone()); - discr.setOrder(order); - LensProjectionContext otherCtx = context.createProjectionContext(discr); - otherCtx.setResource(origProjectionContext.getResource()); - // Force recon for the new context. This is a primitive way how to avoid phantom changes. - otherCtx.setDoReconciliation(true); - return otherCtx; - } - - /** - * Check that the dependencies are still satisfied. Also check for high-ordes vs low-order operation consistency - * and stuff like that. - */ - private boolean checkDependencies(LensContext context, - LensProjectionContext projContext) throws PolicyViolationException { - if (projContext.isDelete()) { - // It is OK if we depend on something that is not there if we are being removed ... for now - return true; - } - - if (projContext.getOid() == null || projContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD) { - // Check for lower-order contexts - LensProjectionContext lowerOrderContext = null; - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - if (projContext == projectionContext) { - continue; - } - if (projectionContext.compareResourceShadowDiscriminator(projContext.getResourceShadowDiscriminator(), false) && - projectionContext.getResourceShadowDiscriminator().getOrder() < projContext.getResourceShadowDiscriminator().getOrder()) { - if (projectionContext.getOid() != null) { - lowerOrderContext = projectionContext; - break; - } - } - } - if (lowerOrderContext != null) { - if (lowerOrderContext.getOid() != null) { - if (projContext.getOid() == null) { - projContext.setOid(lowerOrderContext.getOid()); - } - if (projContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD) { - // This context cannot be ADD. There is a lower-order context with an OID - // it means that the lower-order projection exists, we cannot add it twice - projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.KEEP); - } - } - if (lowerOrderContext.isDelete()) { - projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.DELETE); - } - } - } - - for (ResourceObjectTypeDependencyType dependency: projContext.getDependencies()) { - ResourceShadowDiscriminator refRat = new ResourceShadowDiscriminator(dependency, - projContext.getResource().getOid(), projContext.getKind()); - LOGGER.trace("LOOKING FOR {}", refRat); - LensProjectionContext dependencyAccountContext = context.findProjectionContext(refRat); - ResourceObjectTypeDependencyStrictnessType strictness = ResourceTypeUtil.getDependencyStrictness(dependency); - if (dependencyAccountContext == null) { - if (strictness == ResourceObjectTypeDependencyStrictnessType.STRICT) { - // This should not happen, it is checked before projection - throw new PolicyViolationException("Unsatisfied strict dependency of " - + projContext.getResourceShadowDiscriminator().toHumanReadableString() + - " dependent on " + refRat.toHumanReadableString() + ": No context in dependency check"); - } else if (strictness == ResourceObjectTypeDependencyStrictnessType.LAX) { - // independent object not in the context, just ignore it - LOGGER.trace("Unsatisfied lax dependency of account " + - projContext.getResourceShadowDiscriminator().toHumanReadableString() + - " dependent on " + refRat.toHumanReadableString() + "; dependency skipped"); - } else if (strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) { - // independent object not in the context, just ignore it - LOGGER.trace("Unsatisfied relaxed dependency of account " - + projContext.getResourceShadowDiscriminator().toHumanReadableString() + - " dependent on " + refRat.toHumanReadableString() + "; dependency skipped"); - } else { - throw new IllegalArgumentException("Unknown dependency strictness "+dependency.getStrictness()+" in "+refRat); - } - } else { - // We have the context of the object that we depend on. We need to check if it was provisioned. - if (strictness == ResourceObjectTypeDependencyStrictnessType.STRICT - || strictness == ResourceObjectTypeDependencyStrictnessType.RELAXED) { - if (wasProvisioned(dependencyAccountContext, context.getExecutionWave())) { - // everything OK - } else { - // We do not want to throw exception here. That will stop entire projection. - // Let's just mark the projection as broken and skip it. - LOGGER.warn("Unsatisfied dependency of account "+projContext.getResourceShadowDiscriminator()+ - " dependent on "+refRat+": Account not provisioned in dependency check (execution wave "+context.getExecutionWave()+", account wave "+projContext.getWave() + ", depenedency account wave "+dependencyAccountContext.getWave()+")"); - projContext.setSynchronizationPolicyDecision(SynchronizationPolicyDecision.BROKEN); - return false; - } - } else if (strictness == ResourceObjectTypeDependencyStrictnessType.LAX) { - // we don't care what happened, just go on - return true; - } else { - throw new IllegalArgumentException("Unknown dependency strictness "+dependency.getStrictness()+" in "+refRat); - } - } - } - return true; - } - - /** - * Finally checks for all the dependencies. Some dependencies cannot be checked during wave computations as - * we might not have all activation decisions yet. - */ - private void checkDependenciesFinal(LensContext context) throws PolicyViolationException { - - for (LensProjectionContext accountContext: context.getProjectionContexts()) { - checkDependencies(context, accountContext); - } - - for (LensProjectionContext accountContext: context.getProjectionContexts()) { - if (accountContext.isDelete() - || accountContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.UNLINK) { - // It is OK if we depend on something that is not there if we are being removed - // but we still need to check if others depends on me - for (LensProjectionContext projectionContext: context.getProjectionContexts()) { - if (projectionContext.isDelete() - || projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.UNLINK - || projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN - || projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) { - // If someone who is being deleted depends on us then it does not really matter - continue; - } - for (ResourceObjectTypeDependencyType dependency: projectionContext.getDependencies()) { - if (dependency.getResourceRef().getOid().equals(accountContext.getResource().getOid())) { - // Someone depends on us - if (ResourceTypeUtil.getDependencyStrictness(dependency) == ResourceObjectTypeDependencyStrictnessType.STRICT) { - throw new PolicyViolationException("Cannot remove "+accountContext.getHumanReadableName() - +" because "+projectionContext.getHumanReadableName()+" depends on it"); - } - } - } - } - - } - } - } - - private boolean wasProvisioned(LensProjectionContext accountContext, int executionWave) { - int accountWave = accountContext.getWave(); - if (accountWave >= executionWave) { - // This had no chance to be provisioned yet, so we assume it will be provisioned - return true; - } - if (accountContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN - || accountContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) { - return false; - } - PrismObject objectCurrent = accountContext.getObjectCurrent(); - if (objectCurrent != null && objectCurrent.asObjectable().getFailedOperationType() != null) { - // There is unfinished operation in the shadow. We cannot continue. - return false; - } - if (accountContext.isExists()) { - return true; - } - if (accountContext.isAdd()) { - List> executedDeltas = accountContext.getExecutedDeltas(); - if (executedDeltas == null || executedDeltas.isEmpty()) { - return false; - } - for (LensObjectDeltaOperation executedDelta: executedDeltas) { - OperationResult executionResult = executedDelta.getExecutionResult(); - if (executionResult == null || !executionResult.isSuccess()) { - return false; - } - } - return true; - } - return false; - } - - - } From 9c223b8709156f3f109427b3c930f2e7ecf990b3 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Fri, 25 Jul 2014 12:34:39 +0200 Subject: [PATCH 29/51] Fix for dependencies and deprovisioning (MID-922) --- .../lens/projector/DependencyProcessor.java | 99 +++++++++++-- .../model/impl/lens/projector/Projector.java | 65 +++++---- .../model/impl/lens/TestDependencies.java | 131 ++++++++++++++++-- .../midpoint/testing/story/TestVillage.java | 24 +++- 4 files changed, 267 insertions(+), 52 deletions(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java index 4b27c99ed17..66180d74e1b 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java @@ -101,10 +101,11 @@ public void sortProjectionsToWaves(LensContext context } public int computeMaxWaves(LensContext context) { + // Let's do one extra wave with no accounts in it. This time we expect to get the results of the execution to the user + // via inbound, e.g. identifiers generated by the resource, DNs and similar things. Hence the +2 instead of +1 return context.getMaxWave() + 2; } - - // TODO: check for circular dependencies + private LensProjectionContext determineProjectionWave(LensContext context, LensProjectionContext projectionContext, ResourceObjectTypeDependencyType inDependency, List depPath) throws PolicyViolationException { if (!projectionContext.isWaveIncomplete()) { @@ -112,10 +113,15 @@ private LensProjectionContext determineProjectionWave(Len return projectionContext; } if (projectionContext.isDelete()) { - // Ignore dependencies if we are being removed - projectionContext.setWave(0); - return projectionContext; + // When deprovisioning (deleting) the dependencies needs to be processed in reverse + return determineProjectionWaveDeprovision(context, projectionContext, inDependency, depPath); + } else { + return determineProjectionWaveProvision(context, projectionContext, inDependency, depPath); } + } + + private LensProjectionContext determineProjectionWaveProvision(LensContext context, + LensProjectionContext projectionContext, ResourceObjectTypeDependencyType inDependency, List depPath) throws PolicyViolationException { if (depPath == null) { depPath = new ArrayList(); } @@ -134,7 +140,7 @@ private LensProjectionContext determineProjectionWave(Len depPath.add(outDependency); ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(outDependency, projectionContext.getResource().getOid(), projectionContext.getKind()); - LensProjectionContext dependencyProjectionContext = findDependencyContext(context, projectionContext, outDependency); + LensProjectionContext dependencyProjectionContext = findDependencyTargetContext(context, projectionContext, outDependency); // if (LOGGER.isTraceEnabled()) { // LOGGER.trace("DEP: {} -> {}", refDiscr, dependencyProjectionContext); // } @@ -179,6 +185,71 @@ private LensProjectionContext determineProjectionWave(Len return resultAccountContext; } + private LensProjectionContext determineProjectionWaveDeprovision(LensContext context, + LensProjectionContext projectionContext, ResourceObjectTypeDependencyType inDependency, List depPath) throws PolicyViolationException { + if (depPath == null) { + depPath = new ArrayList(); + } + int determinedWave = 0; + int determinedOrder = 0; + + // This needs to go in the reverse. We need to figure out who depends on us. + for (DependencyAndSource ds: findReverseDependecies(context, projectionContext)) { + LensProjectionContext dependencySourceContext = ds.sourceProjectionContext; + ResourceObjectTypeDependencyType outDependency = ds.dependency; +// if (LOGGER.isTraceEnabled()) { +// LOGGER.trace("DEP(rev): {}", outDependency); +// } + if (inDependency != null && isHigerOrder(outDependency, inDependency)) { + // There is incomming dependency. Deal only with dependencies of this order and lower + // otherwise we can end up in endless loop even for legal dependencies. + continue; + } + checkForCircular(depPath, outDependency); + depPath.add(outDependency); + ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(outDependency, + projectionContext.getResource().getOid(), projectionContext.getKind()); + dependencySourceContext = determineProjectionWave(context, dependencySourceContext, outDependency, depPath); + if (dependencySourceContext.getWave() + 1 > determinedWave) { + determinedWave = dependencySourceContext.getWave() + 1; + if (outDependency.getOrder() == null) { + determinedOrder = 0; + } else { + determinedOrder = outDependency.getOrder(); + } + } + depPath.remove(outDependency); + } + + LensProjectionContext resultAccountContext = projectionContext; + if (projectionContext.getWave() >=0 && projectionContext.getWave() != determinedWave) { + // Wave for this context was set during the run of this method (it was not set when we + // started, we checked at the beginning). Therefore this context must have been visited again. + // therefore there is a circular dependency. Therefore we need to create another context to split it. + resultAccountContext = createAnotherContext(context, projectionContext, determinedOrder); + } +// LOGGER.trace("Wave for {}: {}", resultAccountContext.getResourceAccountType(), wave); + resultAccountContext.setWave(determinedWave); + return resultAccountContext; + } + + private Collection findReverseDependecies(LensContext context, + LensProjectionContext targetProjectionContext) throws PolicyViolationException { + Collection deps = new ArrayList<>(); + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + for (ResourceObjectTypeDependencyType dependency: projectionContext.getDependencies()) { + if (isDependencyTargetContext(projectionContext, targetProjectionContext, dependency)) { + DependencyAndSource ds = new DependencyAndSource(); + ds.dependency = dependency; + ds.sourceProjectionContext = projectionContext; + deps.add(ds); + } + } + } + return deps; + } + + private void checkForCircular(List depPath, ResourceObjectTypeDependencyType outDependency) throws PolicyViolationException { for (ResourceObjectTypeDependencyType pathElement: depPath) { @@ -213,10 +284,10 @@ private boolean isHigerOrder(ResourceObjectTypeDependencyType a, /** * Find context that has the closest order to the dependency. */ - private LensProjectionContext findDependencyContext( - LensContext context, LensProjectionContext projContext, ResourceObjectTypeDependencyType dependency){ + private LensProjectionContext findDependencyTargetContext( + LensContext context, LensProjectionContext sourceProjContext, ResourceObjectTypeDependencyType dependency) { ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(dependency, - projContext.getResource().getOid(), projContext.getKind()); + sourceProjContext.getResource().getOid(), sourceProjContext.getKind()); LensProjectionContext selected = null; for (LensProjectionContext projectionContext: context.getProjectionContexts()) { if (!projectionContext.compareResourceShadowDiscriminator(refDiscr, false)) { @@ -237,6 +308,12 @@ private LensProjectionContext findDependencyContext( return selected; } + private boolean isDependencyTargetContext(LensProjectionContext sourceProjContext, LensProjectionContext targetProjectionContext, ResourceObjectTypeDependencyType dependency) { + ResourceShadowDiscriminator refDiscr = new ResourceShadowDiscriminator(dependency, + sourceProjContext.getResource().getOid(), sourceProjContext.getKind()); + return targetProjectionContext.compareResourceShadowDiscriminator(refDiscr, false); + } + private LensProjectionContext createAnotherContext(LensContext context, LensProjectionContext origProjectionContext, int order) throws PolicyViolationException { ResourceShadowDiscriminator origDiscr = origProjectionContext.getResourceShadowDiscriminator(); @@ -414,6 +491,10 @@ private boolean wasProvisioned(LensProjectionContext acco return false; } + class DependencyAndSource { + ResourceObjectTypeDependencyType dependency; + LensProjectionContext sourceProjectionContext; + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java index 7cc0e68c72d..7c9f8160bf8 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2014 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -137,14 +137,12 @@ public void project(LensContext context, String activi context.setFresh(true); if (consistencyChecks) context.checkConsistence(); - dependencyProcessor.sortProjectionsToWaves(context); - // Let's do one extra wave with no accounts in it. This time we expect to get the results of the execution to the user - // via inbound, e.g. identifiers generated by the resource, DNs and similar things. Hence the +2 instead of +1 - int maxWaves = dependencyProcessor.computeMaxWaves(context); - // Note that the number of waves may be recomputed as new accounts appear in the context (usually after assignment step). + // For now let's pretend to do just one wave. The maxWaves number will be corrected in the + // first wave when dependencies are sorted out for the first time. + int maxWaves = 1; // Start the waves .... - LOGGER.trace("WAVE: Starting the waves. There will be {} waves (or so we think now)", maxWaves); + LOGGER.trace("WAVE: Starting the waves."); context.setProjectionWave(0); while (context.getProjectionWave() < maxWaves) { @@ -156,6 +154,23 @@ public void project(LensContext context, String activi focusProcessor.processFocus(context, activityDescription, now, task, result); context.recomputeFocus(); if (consistencyChecks) context.checkConsistence(); + + // Process activation of all resources, regardless of the waves. This is needed to properly + // sort projections to waves as deprovisioning will reverse the dependencies. And we know whether + // a projection is provisioned or deprovisioned only after the activation is processed. + if (context.getProjectionWave() == 0) { + LOGGER.trace("Processing activation for all contexts"); + for (LensProjectionContext projectionContext: context.getProjectionContexts()) { + if (projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN || + projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) { + continue; + } + String projectionDesc = getProjectionDesc(projectionContext); + activationProcessor.processActivation(context, projectionContext, now, task, result); + projectionContext.recompute(); + LensUtil.traceContext(LOGGER, activityDescription, "projection activation of "+projectionDesc, false, context, false); + } + } dependencyProcessor.sortProjectionsToWaves(context); maxWaves = dependencyProcessor.computeMaxWaves(context); @@ -172,17 +187,7 @@ public void project(LensContext context, String activi projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) { continue; } - String projectionDesc; - if (projectionContext.getResource() != null) { - projectionDesc = projectionContext.getResource() + "("+projectionContext.getResourceShadowDiscriminator().getIntent()+")"; - } else { - ResourceShadowDiscriminator discr = projectionContext.getResourceShadowDiscriminator(); - if (discr != null) { - projectionDesc = projectionContext.getResourceShadowDiscriminator().toString(); - } else { - projectionDesc = "(UNKNOWN)"; - } - } + String projectionDesc = getProjectionDesc(projectionContext); if (projectionContext.getWave() != context.getProjectionWave()) { // Let's skip accounts that do not belong into this wave. @@ -196,17 +201,6 @@ public void project(LensContext context, String activi if (consistencyChecks) context.checkConsistence(); - activationProcessor.processActivation(context, projectionContext, now, task, result); - - projectionContext.recompute(); - - LensUtil.traceContext(LOGGER, activityDescription, "projection activation of "+projectionDesc, false, context, false); - - if (projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.BROKEN || - projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) { - continue; - } - if (!dependencyProcessor.checkDependencies(context, projectionContext)) { continue; } @@ -295,6 +289,19 @@ public void project(LensContext context, String activi } + private String getProjectionDesc(LensProjectionContext projectionContext) { + if (projectionContext.getResource() != null) { + return projectionContext.getResource() + "("+projectionContext.getResourceShadowDiscriminator().getIntent()+")"; + } else { + ResourceShadowDiscriminator discr = projectionContext.getResourceShadowDiscriminator(); + if (discr != null) { + return projectionContext.getResourceShadowDiscriminator().toString(); + } else { + return "(UNKNOWN)"; + } + } + } + private void addConflictingContexts(LensContext context) { List conflictingContexts = projectionValuesProcessor.getConflictingContexts(); if (conflictingContexts != null || !conflictingContexts.isEmpty()){ diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java index ab095d007d2..e2852d38213 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestDependencies.java @@ -37,8 +37,10 @@ import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.model.impl.lens.LensFocusContext; import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; +import com.evolveum.midpoint.model.impl.lens.projector.DependencyProcessor; import com.evolveum.midpoint.model.impl.lens.projector.Projector; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; @@ -70,6 +72,9 @@ public class TestDependencies extends AbstractInternalModelIntegrationTest { @Autowired(required = true) private Projector projector; + @Autowired(required = true) + private DependencyProcessor dependencyProcessor; + @Autowired(required = true) private TaskManager taskManager; @@ -113,7 +118,7 @@ private String getDummuAccountOid(String dummyName, String accountName) { @Test public void test100SortToWavesIdependent() throws Exception { - final String TEST_NAME = "test100SortToWaves"; + final String TEST_NAME = "test100SortToWavesIdependent"; TestUtil.displayTestTile(this, TEST_NAME); // GIVEN @@ -131,7 +136,7 @@ public void test100SortToWavesIdependent() throws Exception { context.checkConsistence(); // WHEN - projector.sortProjectionsToWaves(context); + dependencyProcessor.sortProjectionsToWaves(context); // THEN display("Context after", context); @@ -161,7 +166,7 @@ public void test101SortToWavesAB() throws Exception { context.checkConsistence(); // WHEN - projector.sortProjectionsToWaves(context); + dependencyProcessor.sortProjectionsToWaves(context); // THEN display("Context after", context); @@ -194,7 +199,7 @@ public void test102SortToWavesABCD() throws Exception { context.checkConsistence(); // WHEN - projector.sortProjectionsToWaves(context); + dependencyProcessor.sortProjectionsToWaves(context); // THEN display("Context after", context); @@ -227,7 +232,7 @@ public void test120SortToWavesBCUnsatisfied() throws Exception { try { // WHEN - projector.sortProjectionsToWaves(context); + dependencyProcessor.sortProjectionsToWaves(context); display("Context after", context); AssertJUnit.fail("Unexpected success"); @@ -238,8 +243,8 @@ public void test120SortToWavesBCUnsatisfied() throws Exception { @Test - public void test201SortToWavesPR() throws Exception { - final String TEST_NAME = "test201SortToWavesPR"; + public void test151SortToWavesPR() throws Exception { + final String TEST_NAME = "test151SortToWavesPR"; TestUtil.displayTestTile(this, TEST_NAME); // GIVEN @@ -257,7 +262,7 @@ public void test201SortToWavesPR() throws Exception { context.checkConsistence(); // WHEN - projector.sortProjectionsToWaves(context); + dependencyProcessor.sortProjectionsToWaves(context); // THEN display("Context after", context); @@ -272,8 +277,8 @@ public void test201SortToWavesPR() throws Exception { * in different order of computation. */ @Test - public void test202SortToWavesRP() throws Exception { - final String TEST_NAME = "test202SortToWavesRP"; + public void test152SortToWavesRP() throws Exception { + final String TEST_NAME = "test152SortToWavesRP"; TestUtil.displayTestTile(this, TEST_NAME); // GIVEN @@ -291,7 +296,7 @@ public void test202SortToWavesRP() throws Exception { context.checkConsistence(); // WHEN - projector.sortProjectionsToWaves(context); + dependencyProcessor.sortProjectionsToWaves(context); // THEN display("Context after", context); @@ -301,6 +306,108 @@ public void test202SortToWavesRP() throws Exception { assertWave(context, getDummyOid("p"), 5, 2); } + @Test + public void test200SortToWavesIdependentDeprovision() throws Exception { + final String TEST_NAME = "test200SortToWavesIdependentDeprovision"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestDependencies.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + LensContext context = createUserAccountContext(); + LensFocusContext focusContext = fillContextWithUser(context, USER_ELAINE_OID, result); + LensProjectionContext accountContext = fillContextWithAccount(context, ACCOUNT_SHADOW_ELAINE_DUMMY_OID, result); + setDelete(accountContext); + setDelete(fillContextWithDummyElaineAccount(context, "a", result)); + + context.recompute(); + display("Context before", context); + context.checkConsistence(); + + // WHEN + dependencyProcessor.sortProjectionsToWaves(context); + + // THEN + display("Context after", context); + + assertWave(context, RESOURCE_DUMMY_OID, 0, 0); + assertWave(context, getDummyOid("a"), 0, 0); + } + + @Test + public void test201SortToWavesABDeprovision() throws Exception { + final String TEST_NAME = "test201SortToWavesABDeprovision"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestDependencies.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + LensContext context = createUserAccountContext(); + LensFocusContext focusContext = fillContextWithUser(context, USER_ELAINE_OID, result); + LensProjectionContext accountContext = fillContextWithAccount(context, ACCOUNT_SHADOW_ELAINE_DUMMY_OID, result); + setDelete(accountContext); + setDelete(fillContextWithDummyElaineAccount(context, "a", result)); + setDelete(fillContextWithDummyElaineAccount(context, "b", result)); + + context.recompute(); + display("Context before", context); + context.checkConsistence(); + + // WHEN + dependencyProcessor.sortProjectionsToWaves(context); + + // THEN + display("Context after", context); + + assertWave(context, RESOURCE_DUMMY_OID, 0, 0); + assertWave(context, getDummyOid("a"), 0, 1); + assertWave(context, getDummyOid("b"), 0, 0); + } + + @Test + public void test202SortToWavesABCDDeprovision() throws Exception { + final String TEST_NAME = "test202SortToWavesABCDDeprovision"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestDependencies.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + LensContext context = createUserAccountContext(); + LensFocusContext focusContext = fillContextWithUser(context, USER_ELAINE_OID, result); + LensProjectionContext accountContext = fillContextWithAccount(context, ACCOUNT_SHADOW_ELAINE_DUMMY_OID, result); + setDelete(accountContext); + setDelete(fillContextWithDummyElaineAccount(context, "a", result)); + setDelete(fillContextWithDummyElaineAccount(context, "b", result)); + setDelete(fillContextWithDummyElaineAccount(context, "c", result)); + setDelete(fillContextWithDummyElaineAccount(context, "d", result)); + + context.recompute(); + display("Context before", context); + context.checkConsistence(); + + // WHEN + dependencyProcessor.sortProjectionsToWaves(context); + + // THEN + display("Context after", context); + + assertWave(context, RESOURCE_DUMMY_OID, 0, 0); + assertWave(context, getDummyOid("a"), 0, 2); + assertWave(context, getDummyOid("b"), 0, 1); + assertWave(context, getDummyOid("c"), 0, 0); + assertWave(context, getDummyOid("d"), 0, 0); + } + + private void setDelete(LensProjectionContext accountContext) { + accountContext.setPrimaryDelta(ObjectDelta.createDeleteDelta(ShadowType.class, accountContext.getOid(), prismContext)); + } + @Test public void test300SortToWavesXYZCircular() throws Exception { final String TEST_NAME = "test300SortToWavesXYZCircular"; @@ -323,7 +430,7 @@ public void test300SortToWavesXYZCircular() throws Exception { try { // WHEN - projector.sortProjectionsToWaves(context); + dependencyProcessor.sortProjectionsToWaves(context); AssertJUnit.fail("Unexpected success"); } catch (PolicyViolationException e) { diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestVillage.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestVillage.java index 5c57e9e8372..636113e0d9c 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestVillage.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/TestVillage.java @@ -705,14 +705,34 @@ public void test300AddProjectJollyRoger() throws Exception { result.computeStatus(); TestUtil.assertSuccess(result); - // TODO PrismObject org = getObject(OrgType.class, ORG_PROJECT_JOLLY_ROGER_OID); display("Org", org); assertLinks(org, 2); SearchResultEntry ouEntry = openDJController.fetchAndAssertEntry("ou=Jolly Roger,dc=example,dc=com", "organizationalUnit"); SearchResultEntry groupEntry = openDJController.fetchAndAssertEntry("cn=admins,ou=Jolly Roger,dc=example,dc=com", "groupOfUniqueNames"); - //TODO: assertions + //TODO: more assertions + } + + @Test + public void test319DeleteProjectJollyRoger() throws Exception { + final String TEST_NAME = "test319DeleteProjectJollyRoger"; + TestUtil.displayTestTile(this, TEST_NAME); + Task task = taskManager.createTaskInstance(TestTrafo.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + deleteObject(OrgType.class, ORG_PROJECT_JOLLY_ROGER_OID, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertNoObject(OrgType.class, ORG_PROJECT_JOLLY_ROGER_OID, task, result); + openDJController.assertNoEntry("ou=Jolly Roger,dc=example,dc=com"); + openDJController.assertNoEntry("cn=admins,ou=Jolly Roger,dc=example,dc=com"); } /** From f773129b043bfcb6b9813c7ef8a0688e4df29cf2 Mon Sep 17 00:00:00 2001 From: Erik Suta Date: Fri, 25 Jul 2014 14:11:42 +0200 Subject: [PATCH 30/51] MID-2010 fix - displaying tenant name for assignments (RoleType) --- .../web/component/assignment/AssignmentEditorDto.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java index 0cad19915be..c68f9ac9f59 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorDto.java @@ -85,8 +85,9 @@ public AssignmentEditorDto(ObjectType targetObject, AssignmentEditorDtoType type // newAssignment.setConstruction(construction.clone()); // } - this.name = getNameForTargetObject(targetObject); this.tenantRef = loadTenantReference(targetObject, assignment, pageBase); + + this.name = getNameForTargetObject(targetObject); } private ObjectViewDto loadTenantReference(ObjectType object, AssignmentType assignment, PageBase page){ @@ -137,12 +138,18 @@ private String getNameForTargetObject(ObjectType object) { builder.append(" (").append(getRelation()).append(')'); } + if(object instanceof RoleType){ + if(tenantRef != null && tenantRef.getOid() != null){ + builder.append(" - ").append(tenantRef.getName()); + } + } + return builder.toString(); } public List getAttributes() { if (attributes == null) { - attributes = new ArrayList(); + attributes = new ArrayList<>(); } return attributes; } From 4bb232340c9d014c95cf46b107606e20102c65d5 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Fri, 25 Jul 2014 15:34:48 +0200 Subject: [PATCH 31/51] Fixing cyclic dependency check error. --- .../impl/lens/projector/DependencyProcessor.java | 16 +++++++++------- .../model/impl/lens/projector/Projector.java | 3 +-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java index 66180d74e1b..40dc48febf8 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/DependencyProcessor.java @@ -114,8 +114,10 @@ private LensProjectionContext determineProjectionWave(Len } if (projectionContext.isDelete()) { // When deprovisioning (deleting) the dependencies needs to be processed in reverse + LOGGER.trace("Determining wave for (deprovision): {}", projectionContext); return determineProjectionWaveDeprovision(context, projectionContext, inDependency, depPath); } else { + LOGGER.trace("Determining wave for (provision): {}", projectionContext); return determineProjectionWaveProvision(context, projectionContext, inDependency, depPath); } } @@ -128,9 +130,9 @@ private LensProjectionContext determineProjectionWaveProv int determinedWave = 0; int determinedOrder = 0; for (ResourceObjectTypeDependencyType outDependency: projectionContext.getDependencies()) { -// if (LOGGER.isTraceEnabled()) { -// LOGGER.trace("DEP: {}", outDependency); -// } + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("DEP: {}", outDependency); + } if (inDependency != null && isHigerOrder(outDependency, inDependency)) { // There is incomming dependency. Deal only with dependencies of this order and lower // otherwise we can end up in endless loop even for legal dependencies. @@ -144,7 +146,7 @@ private LensProjectionContext determineProjectionWaveProv // if (LOGGER.isTraceEnabled()) { // LOGGER.trace("DEP: {} -> {}", refDiscr, dependencyProjectionContext); // } - if (dependencyProjectionContext == null) { + if (dependencyProjectionContext == null || dependencyProjectionContext.isDelete()) { ResourceObjectTypeDependencyStrictnessType outDependencyStrictness = ResourceTypeUtil.getDependencyStrictness(outDependency); if (outDependencyStrictness == ResourceObjectTypeDependencyStrictnessType.STRICT) { throw new PolicyViolationException("Unsatisfied strict dependency of account "+projectionContext.getResourceShadowDiscriminator()+ @@ -197,9 +199,9 @@ private LensProjectionContext determineProjectionWaveDepr for (DependencyAndSource ds: findReverseDependecies(context, projectionContext)) { LensProjectionContext dependencySourceContext = ds.sourceProjectionContext; ResourceObjectTypeDependencyType outDependency = ds.dependency; -// if (LOGGER.isTraceEnabled()) { -// LOGGER.trace("DEP(rev): {}", outDependency); -// } + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("DEP(rev): {}", outDependency); + } if (inDependency != null && isHigerOrder(outDependency, inDependency)) { // There is incomming dependency. Deal only with dependencies of this order and lower // otherwise we can end up in endless loop even for legal dependencies. diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java index 7c9f8160bf8..8b6ba94bef3 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/Projector.java @@ -165,12 +165,11 @@ public void project(LensContext context, String activi projectionContext.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.IGNORE) { continue; } - String projectionDesc = getProjectionDesc(projectionContext); activationProcessor.processActivation(context, projectionContext, now, task, result); projectionContext.recompute(); - LensUtil.traceContext(LOGGER, activityDescription, "projection activation of "+projectionDesc, false, context, false); } } + LensUtil.traceContext(LOGGER, activityDescription, "projection activation of all resources", false, context, false); dependencyProcessor.sortProjectionsToWaves(context); maxWaves = dependencyProcessor.computeMaxWaves(context); From ecf5a316158b5881061933701458fcb02da313dc Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Mon, 28 Jul 2014 18:35:51 +0200 Subject: [PATCH 32/51] implementing MID-2009 * used existing resource schema attribute - naming attribute * mapping this attribute to the shadow/name * changed search filter from substring: shadow/attributes/secondaryIdentifier to shadow/attributes/namingAttribute.. --- .../content/PageContentAccounts.java | 6 ++++-- .../midpoint/schema/util/ShadowUtil.java | 14 +++++++++++++- .../provisioning/impl/ShadowCache.java | 7 ++++--- .../provisioning/util/ProvisioningUtil.java | 19 +++++++++++++++++-- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageContentAccounts.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageContentAccounts.java index 7cdb145c6d4..53a8e112541 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageContentAccounts.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/content/PageContentAccounts.java @@ -558,8 +558,10 @@ private ObjectQuery createQuery() { if (dto.isName()) { List secondaryIdentifiers = new ArrayList<>(); - if (def.getSecondaryIdentifiers() != null) { - secondaryIdentifiers.addAll(def.getSecondaryIdentifiers()); + if (def.getNamingAttribute() != null) { + secondaryIdentifiers.add(def.getNamingAttribute()); + } else if (def.getSecondaryIdentifiers() != null){ + secondaryIdentifiers.addAll(def.getSecondaryIdentifiers()); } for (ResourceAttributeDefinition attrDef : secondaryIdentifiers) { conditions.add(SubstringFilter.createSubstring( diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ShadowUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ShadowUtil.java index 3bc82d748fa..7945bdedc98 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ShadowUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ShadowUtil.java @@ -67,6 +67,18 @@ public static Collection> getSecondaryIdentifiers(PrismObje return attributesContainer.getSecondaryIdentifiers(); } + public static ResourceAttribute getNamingAttribute(ShadowType shadow){ + return getNamingAttribute(shadow.asPrismObject()); + } + + public static ResourceAttribute getNamingAttribute(PrismObject shadow) { + ResourceAttributeContainer attributesContainer = getAttributesContainer(shadow); + if (attributesContainer == null) { + return null; + } + return attributesContainer.getNamingAttribute(); + } + public static Collection> getAttributes(ShadowType shadowType) { return getAttributes(shadowType.asPrismObject()); } @@ -148,7 +160,7 @@ public static String getSingleStringAttributeValue(ShadowType shadow, QName attr } - private static String getSingleStringAttributeValue(PrismObject shadow, QName attrName) { + public static String getSingleStringAttributeValue(PrismObject shadow, QName attrName) { PrismContainer attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); if (attributesContainer == null) { return null; diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java index 4632ce0ffb9..0aeab11ab51 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java @@ -445,7 +445,7 @@ public String modifyShadow(PrismObject shadow, ResourceType resource afterModifyOnResource(shadow, modifications, parentResult); - Collection> renameDeltas = distillRenameDeltas(modifications, shadow, objectClassDefinition); + Collection> renameDeltas = distillRenameDeltas(modifications, shadow, objectClassDefinition, task, parentResult); Collection sideEffectDelta = convertToPropertyDelta(sideEffectChanges); if (renameDeltas != null) { @@ -472,7 +472,7 @@ public String modifyShadow(PrismObject shadow, ResourceType resource } private Collection> distillRenameDeltas(Collection modifications, - PrismObject shadow, RefinedObjectClassDefinition objectClassDefinition) throws SchemaException { + PrismObject shadow, RefinedObjectClassDefinition objectClassDefinition, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { PropertyDelta nameDelta = (PropertyDelta) ItemDelta.findItemDelta(modifications, new ItemPath(ShadowType.F_ATTRIBUTES, ConnectorFactoryIcfImpl.ICFS_NAME), ItemDelta.class); if (nameDelta == null){ return null; @@ -493,8 +493,9 @@ private Collection> distillRenameDeltas(Collection fullShadow = getShadow(shadow.getOid(), shadow, null, task, parentResult); PropertyDelta shadowNameDelta = PropertyDelta.createModificationReplaceProperty(ShadowType.F_NAME, shadow.getDefinition(), - new PolyString(newName)); + ProvisioningUtil.determineShadowName(fullShadow)); deltas.add(shadowNameDelta); } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java index 965eb635f92..ba5a463e04c 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java @@ -17,6 +17,7 @@ package com.evolveum.midpoint.provisioning.util; import com.evolveum.midpoint.common.StaticExpressionUtil; +import com.evolveum.midpoint.common.Utils; import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.prism.*; @@ -129,7 +130,8 @@ public static PolyString determineShadowName(PrismObject< public static String determineShadowStringName(PrismObject shadow) throws SchemaException { ResourceAttributeContainer attributesContainer = ShadowUtil.getAttributesContainer(shadow); - if (attributesContainer.getNamingAttribute() == null) { + ResourceAttribute namingAttribute = attributesContainer.getNamingAttribute(); + if (namingAttribute == null || namingAttribute.isEmpty()) { // No naming attribute defined. Try to fall back to identifiers. Collection> identifiers = attributesContainer.getIdentifiers(); // We can use only single identifiers (not composite) @@ -153,7 +155,20 @@ public static String determineShadowStringName(PrismObjec throw new SchemaException("No naming attribute defined (and identifier not usable)"); } // TODO: Error handling - return attributesContainer.getNamingAttribute().getValue().getValue(); + List> possibleValues = namingAttribute.getValues(); + + if (possibleValues.size() > 1){ + throw new SchemaException("Cannot determine name of shadow. Found more than one value for naming attribute (attr: "+namingAttribute.getElementName()+", values: {}"+possibleValues+")" ); + } + + PrismPropertyValue value = possibleValues.iterator().next(); + + if (value == null){ + throw new SchemaException("Naming attribute has no value. Could not determine shadow name."); + } + + return value.getValue(); +// return attributesContainer.getNamingAttribute().getValue().getValue(); } From 10608f8e37e9ef25552e802cc53901615ddd923b Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Tue, 29 Jul 2014 16:35:43 +0200 Subject: [PATCH 33/51] fixing test..imroving rename operation.. --- .../impl/ResourceObjectConverter.java | 128 ++++++++++++++++-- .../provisioning/impl/ShadowCache.java | 78 +++++------ .../provisioning/impl/ShadowManager.java | 43 ++++++ .../api/PropertyModificationOperation.java | 4 +- .../provisioning/util/ProvisioningUtil.java | 4 + 5 files changed, 208 insertions(+), 49 deletions(-) diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java index 04f1d9310cf..7969ad97f16 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java @@ -62,6 +62,7 @@ import com.evolveum.midpoint.provisioning.ucf.api.Operation; import com.evolveum.midpoint.provisioning.ucf.api.PropertyModificationOperation; import com.evolveum.midpoint.provisioning.ucf.api.ResultHandler; +import com.evolveum.midpoint.provisioning.ucf.impl.ConnectorFactoryIcfImpl; import com.evolveum.midpoint.provisioning.util.ProvisioningUtil; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; @@ -71,9 +72,10 @@ import com.evolveum.midpoint.schema.processor.ResourceSchema; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; -import com.evolveum.midpoint.schema.util.ShadowUtil; import com.evolveum.midpoint.schema.util.ResourceTypeUtil; import com.evolveum.midpoint.schema.util.SchemaDebugUtil; +import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.Holder; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.PrettyPrinter; @@ -130,7 +132,7 @@ public class ResourceObjectConverter { @Autowired(required=true) private PrismContext prismContext; - private PrismObjectDefinition shadowTypeDefinition; +// private PrismObjectDefinition shadowTypeDefinition; private static final Trace LOGGER = TraceManager.getTrace(ResourceObjectConverter.class); @@ -432,8 +434,17 @@ public Collection modifyResourceObject( "Unable to modify account in the resource. Probably it has not been created yet because of previous unavailability of the resource."); } +// PrismObject currentShadow = null; + if (avoidDuplicateValues(resource) || isRename(operations)) { + // We need to filter out the deltas that add duplicate values or remove values that are not there + shadow = fetchResourceObject(connector, resource, objectClassDefinition, identifiers, null, parentResult); + } + // Execute primary ICF operation on this shadow - sideEffectChanges = executeModify(connector, resource, objectClassDefinition, identifiers, operations, parentResult); + sideEffectChanges = executeModify(connector, resource, shadow, objectClassDefinition, identifiers, operations, parentResult); + + + } /* @@ -444,6 +455,11 @@ public Collection modifyResourceObject( for (ItemDelta itemDelta : itemDeltas) { itemDelta.applyTo(shadowAfter); } + + if (isRename(operations)){ + Collection renameOperations = distillRenameDeltas(itemDeltas, shadowAfter, objectClassDefinition); + sideEffectChanges.addAll(renameOperations); + } // Execute entitlement modification on other objects (if needed) executeEntitlementChangesModify(connector, resource, objectClassDefinition, shadowBefore, shadowAfter, scripts, itemDeltas, parentResult); @@ -452,7 +468,7 @@ public Collection modifyResourceObject( return sideEffectChanges; } - private Collection executeModify(ConnectorInstance connector, ResourceType resource, + private Collection executeModify(ConnectorInstance connector, ResourceType resource, PrismObject currentShadow, RefinedObjectClassDefinition objectClassDefinition, Collection> identifiers, Collection operations, OperationResult parentResult) throws ObjectNotFoundException, CommunicationException, SchemaException, SecurityViolationException, ConfigurationException, ObjectAlreadyExistsException { Collection sideEffectChanges = null; @@ -464,10 +480,14 @@ private Collection executeModify(ConnectorInstanc // Invoke ICF try { - if (avoidDuplicateValues(resource)) { - // We need to filter out the deltas that add duplicate values or remove values that are not there + + + if (avoidDuplicateValues(resource)){ + + if (currentShadow == null){ + currentShadow = fetchResourceObject(connector, resource, objectClassDefinition, identifiers, null, parentResult); + } - PrismObject currentShadow = fetchResourceObject(connector, resource, objectClassDefinition, identifiers, null, parentResult); Collection filteredOperations = new ArrayList(operations.size()); for (Operation origOperation: operations) { if (origOperation instanceof PropertyModificationOperation) { @@ -506,7 +526,8 @@ private Collection executeModify(ConnectorInstanc sideEffectChanges = connector.modifyObject(objectClassDefinition, identifiers, operations, parentResult); - + + LOGGER.debug("PROVISIONING MODIFY successful, side-effect changes {}", SchemaDebugUtil.debugDump(sideEffectChanges)); @@ -540,6 +561,95 @@ private Collection executeModify(ConnectorInstanc return sideEffectChanges; } + private boolean isRename(Collection modifications){ + for (Operation op : modifications){ + if (!(op instanceof PropertyModificationOperation)){ + continue; + } + + if (((PropertyModificationOperation)op).getPropertyDelta().getPath().equals(new ItemPath(ShadowType.F_ATTRIBUTES, ConnectorFactoryIcfImpl.ICFS_NAME))){ + return true; + } + } + return false; +// return ItemDelta.findItemDelta(modifications, new ItemPath(ShadowType.F_ATTRIBUTES, ConnectorFactoryIcfImpl.ICFS_NAME), ItemDelta.class) != null; + } + +// private Collection distillRenameDeltas(Collection modifications, +// PrismObject shadow, RefinedObjectClassDefinition objectClassDefinition) throws SchemaException { +// +// PropertyModificationOperation nameDelta =null; +// +// for (Operation op : modifications){ +// +// if (!(op instanceof PropertyModificationOperation)){ +// continue; +// } +// +// if (((PropertyModificationOperation)op).getPropertyDelta().getPath().equals(new ItemPath(ShadowType.F_ATTRIBUTES, ConnectorFactoryIcfImpl.ICFS_NAME))){ +// nameDelta = (PropertyModificationOperation) op; +// } +// } +// +// PropertyDelta namePropertyDelta = nameDelta.getPropertyDelta(); +// +// PrismProperty name = namePropertyDelta.getPropertyNew(); +// String newName = name.getRealValue(); +// +// Collection deltas = new ArrayList(); +// +// // $shadow/attributes/icfs:name +//// String normalizedNewName = shadowManager.getNormalizedAttributeValue(name.getValue(), objectClassDefinition.findAttributeDefinition(name.getElementName())); +// PropertyDelta cloneNameDelta = namePropertyDelta.clone(); +// cloneNameDelta.clearValuesToReplace(); +// cloneNameDelta.setValueToReplace(new PrismPropertyValue(newName)); +// PropertyModificationOperation operation = new PropertyModificationOperation(cloneNameDelta); +// deltas.add(operation); +// +// // $shadow/name +// if (!newName.equals(shadow.asObjectable().getName().getOrig())){ +// +// PropertyDelta shadowNameDelta = PropertyDelta.createModificationReplaceProperty(ShadowType.F_NAME, shadow.getDefinition(), +// ProvisioningUtil.determineShadowName(shadow)); +// operation = new PropertyModificationOperation(shadowNameDelta); +// deltas.add(operation); +// } +// +// return deltas; +//} + private Collection distillRenameDeltas(Collection modifications, + PrismObject shadow, RefinedObjectClassDefinition objectClassDefinition) throws SchemaException { + + PropertyDelta nameDelta = (PropertyDelta) ItemDelta.findItemDelta(modifications, new ItemPath(ShadowType.F_ATTRIBUTES, ConnectorFactoryIcfImpl.ICFS_NAME), ItemDelta.class); + if (nameDelta == null){ + return null; + } + + PrismProperty name = nameDelta.getPropertyNew(); + String newName = name.getRealValue(); + + Collection deltas = new ArrayList(); + + // $shadow/attributes/icfs:name +// String normalizedNewName = shadowManager.getNormalizedAttributeValue(name.getValue(), objectClassDefinition.findAttributeDefinition(name.getElementName())); + PropertyDelta cloneNameDelta = nameDelta.clone(); + cloneNameDelta.clearValuesToReplace(); + cloneNameDelta.setValueToReplace(new PrismPropertyValue(newName)); + PropertyModificationOperation operation = new PropertyModificationOperation(cloneNameDelta); + deltas.add(operation); + + // $shadow/name +// if (!newName.equals(shadow.asObjectable().getName().getOrig())){ + + PropertyDelta shadowNameDelta = PropertyDelta.createModificationReplaceProperty(ShadowType.F_NAME, shadow.getDefinition(), + ProvisioningUtil.determineShadowName(shadow)); + operation = new PropertyModificationOperation(shadowNameDelta); + deltas.add(operation); +// } + + return deltas; + } + private void executeEntitlementChangesAdd(ConnectorInstance connector, ResourceType resource, RefinedObjectClassDefinition objectClassDefinition, PrismObject shadow, OperationProvisioningScriptsType scripts, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, SecurityViolationException, ConfigurationException, ObjectAlreadyExistsException { @@ -613,7 +723,7 @@ private void executeEntitlements(ConnectorInstance connector, ResourceType resou // TODO: better handling of result, partial failures, etc. - executeModify(connector, resource, ocDef, identifiers, operations, parentResult); + executeModify(connector, resource, null, ocDef, identifiers, operations, parentResult); } } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java index 0aeab11ab51..254a64b2c29 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java @@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import com.evolveum.midpoint.common.Utils; import com.evolveum.midpoint.common.monitor.InternalMonitor; import com.evolveum.midpoint.common.refinery.RefinedAssociationDefinition; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; @@ -445,15 +446,16 @@ public String modifyShadow(PrismObject shadow, ResourceType resource afterModifyOnResource(shadow, modifications, parentResult); - Collection> renameDeltas = distillRenameDeltas(modifications, shadow, objectClassDefinition, task, parentResult); +// Collection> renameDeltas = distillRenameDeltas(modifications, shadow, objectClassDefinition, task, parentResult); - Collection sideEffectDelta = convertToPropertyDelta(sideEffectChanges); - if (renameDeltas != null) { - ((Collection) sideEffectDelta).addAll(renameDeltas); - } + Collection> sideEffectDelta = convertToPropertyDelta(sideEffectChanges); +// shadowManager. +// if (renameDeltas != null) { +// ((Collection) sideEffectDelta).addAll(renameDeltas); +// } if (!sideEffectDelta.isEmpty()) { try { - + shadowManager.normalizeDeltas(sideEffectDelta, objectClassDefinition); repositoryService.modifyObject(shadow.getCompileTimeClass(), oid, sideEffectDelta, parentResult); } catch (ObjectAlreadyExistsException ex) { @@ -471,40 +473,40 @@ public String modifyShadow(PrismObject shadow, ResourceType resource return oid; } - private Collection> distillRenameDeltas(Collection modifications, - PrismObject shadow, RefinedObjectClassDefinition objectClassDefinition, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { - PropertyDelta nameDelta = (PropertyDelta) ItemDelta.findItemDelta(modifications, new ItemPath(ShadowType.F_ATTRIBUTES, ConnectorFactoryIcfImpl.ICFS_NAME), ItemDelta.class); - if (nameDelta == null){ - return null; - } - - PrismProperty name = nameDelta.getPropertyNew(); - String newName = name.getRealValue(); - - Collection> deltas = new ArrayList>(); - - // $shadow/attributes/icfs:name - String normalizedNewName = shadowManager.getNormalizedAttributeValue(name.getValue(), objectClassDefinition.findAttributeDefinition(name.getElementName())); - PropertyDelta cloneNameDelta = nameDelta.clone(); - cloneNameDelta.clearValuesToReplace(); - cloneNameDelta.setValueToReplace(new PrismPropertyValue(normalizedNewName)); - deltas.add(cloneNameDelta); - - // $shadow/name - if (!newName.equals(shadow.asObjectable().getName().getOrig())){ - - PrismObject fullShadow = getShadow(shadow.getOid(), shadow, null, task, parentResult); - PropertyDelta shadowNameDelta = PropertyDelta.createModificationReplaceProperty(ShadowType.F_NAME, shadow.getDefinition(), - ProvisioningUtil.determineShadowName(fullShadow)); - deltas.add(shadowNameDelta); - } - - return deltas; - } +// private Collection> distillRenameDeltas(Collection modifications, +// PrismObject shadow, RefinedObjectClassDefinition objectClassDefinition, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { +// PropertyDelta nameDelta = (PropertyDelta) ItemDelta.findItemDelta(modifications, new ItemPath(ShadowType.F_ATTRIBUTES, ConnectorFactoryIcfImpl.ICFS_NAME), ItemDelta.class); +// if (nameDelta == null){ +// return null; +// } +// +// PrismProperty name = nameDelta.getPropertyNew(); +// String newName = name.getRealValue(); +// +// Collection> deltas = new ArrayList>(); +// +// // $shadow/attributes/icfs:name +// String normalizedNewName = shadowManager.getNormalizedAttributeValue(name.getValue(), objectClassDefinition.findAttributeDefinition(name.getElementName())); +// PropertyDelta cloneNameDelta = nameDelta.clone(); +// cloneNameDelta.clearValuesToReplace(); +// cloneNameDelta.setValueToReplace(new PrismPropertyValue(normalizedNewName)); +// deltas.add(cloneNameDelta); +// +// // $shadow/name +// if (!newName.equals(shadow.asObjectable().getName().getOrig())){ +// +// PrismObject fullShadow = getShadow(shadow.getOid(), shadow, null, task, parentResult); +// PropertyDelta shadowNameDelta = PropertyDelta.createModificationReplaceProperty(ShadowType.F_NAME, shadow.getDefinition(), +// ProvisioningUtil.determineShadowName(fullShadow)); +// deltas.add(shadowNameDelta); +// } +// +// return deltas; +// } - private Collection convertToPropertyDelta( + private Collection> convertToPropertyDelta( Collection sideEffectChanges) { - Collection sideEffectDelta = new ArrayList(); + Collection> sideEffectDelta = new ArrayList>(); if (sideEffectChanges != null) { for (PropertyModificationOperation mod : sideEffectChanges){ sideEffectDelta.add(mod.getPropertyDelta()); diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowManager.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowManager.java index 2666e8b6356..81cb4394dc2 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowManager.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowManager.java @@ -23,6 +23,7 @@ import javax.xml.namespace.QName; +import org.aspectj.weaver.patterns.NamePattern; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @@ -640,6 +641,46 @@ private void normalizeAttribute(ResourceAttribute attribute, RefinedAttri } } + public void normalizeDeltas(Collection>> deltas, + RefinedObjectClassDefinition objectClassDefinition) throws SchemaException { + // TODO Auto-generated method stub + for (ItemDelta> delta : deltas){ + if (!ShadowType.F_ATTRIBUTES.equals(ItemPath.getName(delta.getPath().first()))){ + continue; + } + RefinedAttributeDefinition rAttrDef = objectClassDefinition.findAttributeDefinition(delta.getElementName()); + if (rAttrDef == null){ + throw new SchemaException("Failed to normalize attribute: " + delta.getElementName()+ ". Definition for this attribute doesn't exist."); + } + normalizeDelta(delta, rAttrDef); + } + + + } + + private void normalizeDelta(ItemDelta> delta, RefinedAttributeDefinition rAttrDef) throws SchemaException{ + MatchingRule matchingRule = matchingRuleRegistry.getMatchingRule(rAttrDef.getMatchingRuleQName(), rAttrDef.getTypeName()); + if (matchingRule != null) { + if (delta.getValuesToReplace() != null){ + normalizeValues(delta.getValuesToReplace(), matchingRule); + } + if (delta.getValuesToAdd() != null){ + normalizeValues(delta.getValuesToAdd(), matchingRule); + } + + if (delta.getValuesToDelete() != null){ + normalizeValues(delta.getValuesToDelete(), matchingRule); + } + } + } + + private void normalizeValues(Collection> values, MatchingRule matchingRule){ + for (PrismPropertyValue pval: values) { + T normalizedRealValue = matchingRule.normalize(pval.getValue()); + pval.setValue(normalizedRealValue); + } + } + T getNormalizedAttributeValue(PrismPropertyValue pval, RefinedAttributeDefinition rAttrDef) throws SchemaException { MatchingRule matchingRule = matchingRuleRegistry.getMatchingRule(rAttrDef.getMatchingRuleQName(), rAttrDef.getTypeName()); if (matchingRule != null) { @@ -671,4 +712,6 @@ public boolean compareAttribute(RefinedObjectClassDefinition refinedObjectCl return MiscUtil.unorderedCollectionEquals(valuesA, Arrays.asList(valuesB)); } + + } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/api/PropertyModificationOperation.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/api/PropertyModificationOperation.java index 7192728f2cc..22716292d81 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/api/PropertyModificationOperation.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/api/PropertyModificationOperation.java @@ -30,7 +30,7 @@ public PropertyModificationOperation(PropertyDelta propertyDelta) { super(); this.propertyDelta = propertyDelta; } - + public PropertyDelta getPropertyDelta() { return propertyDelta; } @@ -47,5 +47,5 @@ public String debugDump(int indent) { sb.append(propertyDelta.debugDump(indent+1)); return sb.toString(); } - + } \ No newline at end of file diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java index ba5a463e04c..ac1f0a995b5 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/util/ProvisioningUtil.java @@ -120,6 +120,10 @@ public static void normalizeShadow(T shadow, OperationRes } + public static PolyString determineShadowName(ShadowType shadow) throws SchemaException { + return determineShadowName(shadow.asPrismObject()); + } + public static PolyString determineShadowName(PrismObject shadow) throws SchemaException { String stringName = determineShadowStringName(shadow); if (stringName == null) { From 7e10e5c46ca0c3bfe07268577447303091870fd5 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Tue, 29 Jul 2014 18:07:35 +0200 Subject: [PATCH 34/51] Removed getObject call when deleting objects as administrator. Simplified scripting API a bit + provided rough implementation of PageBulkAction using this API. --- .../admin/configuration/PageBulkAction.java | 58 +++++++++++--- .../evolveum/midpoint/prism/PrismContext.java | 5 ++ .../model/api}/ScriptExecutionException.java | 2 +- .../midpoint/model/api/ScriptingService.java | 38 +++++---- .../midpoint/model/impl/ModelWebService.java | 20 ++--- .../impl/controller/ModelController.java | 16 +++- .../model/impl/scripting/ActionExecutor.java | 1 + .../midpoint/model/impl/scripting/Data.java | 1 + .../scripting/ScriptExecutionTaskHandler.java | 1 + .../ScriptingExpressionEvaluator.java | 37 ++++++--- .../impl/scripting/actions/AddExecutor.java | 2 +- .../scripting/actions/AssignExecutor.java | 3 +- .../scripting/actions/BaseActionExecutor.java | 3 +- .../scripting/actions/DeleteExecutor.java | 2 +- .../actions/DiscoverConnectorsExecutor.java | 7 +- .../actions/EnableDisableExecutor.java | 2 +- .../impl/scripting/actions/LogExecutor.java | 2 +- .../scripting/actions/ModifyExecutor.java | 4 +- .../actions/PurgeSchemaExecutor.java | 2 +- .../scripting/actions/RecomputeExecutor.java | 2 +- .../scripting/actions/ResolveExecutor.java | 2 +- .../actions/TestResourceExecutor.java | 3 +- .../expressions/SearchEvaluator.java | 6 +- .../expressions/SelectEvaluator.java | 4 +- .../scripting/helpers/ExpressionHelper.java | 5 +- .../impl/scripting/helpers/JaxbHelper.java | 56 +++++++++---- .../scripting/helpers/OperationsHelper.java | 2 +- .../intest/scripting/TestScriptingBasic.java | 79 ++++++++++--------- .../testing/model/client/sample/Main.java | 18 ++++- 29 files changed, 239 insertions(+), 144 deletions(-) rename model/{model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting => model-api/src/main/java/com/evolveum/midpoint/model/api}/ScriptExecutionException.java (95%) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java index 50a1b538310..ac5fa157435 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java @@ -16,9 +16,12 @@ package com.evolveum.midpoint.web.page.admin.configuration; +import com.evolveum.midpoint.model.api.ScriptExecutionException; +import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.application.AuthorizationAction; @@ -26,6 +29,7 @@ import com.evolveum.midpoint.web.component.AceEditor; import com.evolveum.midpoint.web.component.AjaxSubmitButton; import com.evolveum.midpoint.web.page.admin.configuration.dto.BulkActionDto; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.Form; @@ -33,15 +37,16 @@ import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; +import javax.xml.bind.JAXBElement; + /** * @author lazyman */ @PageDescriptor(url = "/admin/config/bulk", action = { -// @AuthorizationAction(actionUri = PageAdminConfiguration.AUTH_CONFIGURATION_ALL, -// label = PageAdminConfiguration.AUTH_CONFIGURATION_ALL_LABEL, description = PageAdminConfiguration.AUTH_CONFIGURATION_ALL_DESCRIPTION), -// @AuthorizationAction(actionUri = AuthorizationConstants.NS_AUTHORIZATION + "#bulkAction", -// label = "PageBulkAction.auth.bulkAction.label", description = "PageBulkAction.auth.bulkAction.description") - @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_NO_ACCESS_URL) + @AuthorizationAction(actionUri = PageAdminConfiguration.AUTH_CONFIGURATION_ALL, + label = PageAdminConfiguration.AUTH_CONFIGURATION_ALL_LABEL, description = PageAdminConfiguration.AUTH_CONFIGURATION_ALL_DESCRIPTION), + @AuthorizationAction(actionUri = AuthorizationConstants.NS_AUTHORIZATION + "#bulkAction", + label = "PageBulkAction.auth.bulkAction.label", description = "PageBulkAction.auth.bulkAction.description") }) public class PageBulkAction extends PageAdminConfiguration { @@ -87,12 +92,47 @@ protected void onSubmit(AjaxRequestTarget target, Form form) { } private void startPerformed(AjaxRequestTarget target) { - model.getObject(); - Task task = createSimpleTask(OPERATION_PERFORM_BULK); OperationResult result = new OperationResult(OPERATION_PERFORM_BULK); - //TODO - continue here - we need to find a way to serialize XML String to JAXBElement expression to continue -// getScriptingService().evaluateExpressionInBackground(, task, result); + BulkActionDto bulkActionDto = model.getObject(); + + ScriptingExpressionType expression = null; + try { + Object parsed = getPrismContext().parseAnyValue(bulkActionDto.getScript(), PrismContext.LANG_XML); + if (parsed == null) { + result.recordFatalError("No bulk action object was provided."); + } + if (parsed instanceof JAXBElement) { + parsed = ((JAXBElement) parsed).getValue(); + } + if (parsed instanceof ScriptingExpressionType) { + expression = (ScriptingExpressionType) parsed; + } else { + result.recordFatalError("Provided XML text is not a bulk action object. An instance of {scripting-3}ScriptingExpressionType is expected; you have provided " + parsed.getClass() + " instead."); + } + } catch (SchemaException|RuntimeException e) { + result.recordFatalError("Couldn't parse bulk action object", e); + } + + if (expression != null) { + if (bulkActionDto.isAsync()) { + try { + getScriptingService().evaluateExpressionInBackground(expression, task, result); + } catch (SchemaException e) { + result.recordFatalError("Couldn't submit bulk action to execution because of schema exception", e); + } + } else { + try { + getScriptingService().evaluateExpression(expression, task, result); + } catch (ScriptExecutionException e) { + result.recordFatalError("Couldn't execute bulk action", e); + } + } + } + + result.computeStatusIfUnknown(); + showResult(result); + target.add(getFeedbackPanel()); } } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContext.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContext.java index 64c47fa59bf..e1618167e1d 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContext.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContext.java @@ -391,6 +391,11 @@ public T parseAnyValue(InputStream inputStream, String language) throws Sche return xnodeProcessor.parseAnyValue(xnode); } + public T parseAnyValue(String dataString, String language) throws SchemaException { + XNode xnode = parseToXNode(dataString, language); + return xnodeProcessor.parseAnyValue(xnode); + } + //endregion //region Parsing to XNode diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionException.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptExecutionException.java similarity index 95% rename from model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionException.java rename to model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptExecutionException.java index 47de4648902..cc8d5e58303 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionException.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptExecutionException.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.evolveum.midpoint.model.impl.scripting; +package com.evolveum.midpoint.model.api; /** * Wraps any exceptions that occur during execution of expressions. (ExpressionEvaluationException would be more appropriate, but this name is already used elsewhere.) diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptingService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptingService.java index ae1a4d4322e..994b1ebaa4a 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptingService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptingService.java @@ -16,26 +16,14 @@ package com.evolveum.midpoint.model.api; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.parser.QueryConvertor; import com.evolveum.midpoint.prism.query.ObjectFilter; -import com.evolveum.midpoint.schema.GetOperationOptions; -import com.evolveum.midpoint.schema.SelectorOptions; -import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; -import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ActionExpressionType; -import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ExecuteScriptType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType; -import com.evolveum.midpoint.xml.ns._public.model.scripting_3.SearchExpressionType; import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; -import java.util.Collection; -import java.util.List; /** * Interface of the Model subsystem that provides scripting (bulk actions) operations. @@ -55,6 +43,8 @@ public interface ScriptingService { * and assigns ScriptExecutionTaskHandler to it, to execute the script. * @param parentResult * @throws SchemaException + * + * TODO consider removing this method (it was meant as a simplified version of the method below) */ public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException; @@ -62,11 +52,25 @@ public interface ScriptingService { * Asynchronously executes any scripting expression. * * @param expression Expression to be executed. - * @param task Task in context of which the script should execute. The task should be "clean", i.e. - * (1) transient, (2) without any handler. This method puts the task into background, - * and assigns ScriptExecutionTaskHandler to it, to execute the script. + * @param task Task in context of which the script should execute. + * The task should be "clean", i.e. (1) transient, (2) without any handler. + * This method puts the task into background, and assigns ScriptExecutionTaskHandler + * to it, to execute the script. * @param parentResult * @throws SchemaException */ - public void evaluateExpressionInBackground(JAXBElement expression, Task task, OperationResult parentResult) throws SchemaException; -} + public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException; + + /** + * Synchronously executes any scripting expression (with no input data). + * + * @param expression Scripting expression to execute. + * @param task Task in context of which the script should execute (in foreground!) + * @param result Operation result + * @throws ScriptExecutionException + * + * TODO return ExecutionContext (requires moving the context to model api) + */ + + public void evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException; +} \ No newline at end of file diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java index 0173f86498e..6134d4c3dc2 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java @@ -15,17 +15,13 @@ */ package com.evolveum.midpoint.model.impl; -import com.evolveum.midpoint.audit.api.AuditEventRecord; -import com.evolveum.midpoint.audit.api.AuditEventStage; -import com.evolveum.midpoint.audit.api.AuditEventType; -import com.evolveum.midpoint.audit.api.AuditService; import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.ModelPort; import com.evolveum.midpoint.model.common.util.AbstractModelWebService; import com.evolveum.midpoint.model.impl.controller.ModelController; import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.model.impl.scripting.ScriptingExpressionEvaluator; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismContext; @@ -41,18 +37,14 @@ import com.evolveum.midpoint.schema.constants.ObjectTypes; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; -import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; 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.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; @@ -81,14 +73,12 @@ import com.evolveum.midpoint.xml.ns._public.model.model_3.ExecuteScriptsType; import com.evolveum.midpoint.xml.ns._public.model.model_3.ModelPortType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ItemListType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType; import com.evolveum.prism.xml.ns._public.query_3.QueryType; -import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import com.evolveum.prism.xml.ns._public.types_3.RawType; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import javax.xml.bind.JAXBElement; @@ -275,7 +265,7 @@ private List> parseScripts(ExecuteScriptsType parameters) throws return scriptsToExecute; } - private ExecuteScriptsResponseType doExecuteScripts(List> scriptsToExecute, ExecuteScriptsOptionsType options, Task task, OperationResult result) throws ScriptExecutionException, JAXBException, SchemaException { + private ExecuteScriptsResponseType doExecuteScripts(List> scriptsToExecute, ExecuteScriptsOptionsType options, Task task, OperationResult result) { ExecuteScriptsResponseType response = new ExecuteScriptsResponseType(); ScriptOutputsType outputs = new ScriptOutputsType(); response.setOutputs(outputs); @@ -283,7 +273,7 @@ private ExecuteScriptsResponseType doExecuteScripts(List> scripts try { for (JAXBElement script : scriptsToExecute) { - ExecutionContext outputContext = scriptingExpressionEvaluator.evaluateExpression(script, task, result); + ExecutionContext outputContext = scriptingExpressionEvaluator.evaluateExpression((ScriptingExpressionType) script.getValue(), task, result); SingleScriptOutputType output = new SingleScriptOutputType(); outputs.getOutput().add(output); @@ -298,7 +288,7 @@ private ExecuteScriptsResponseType doExecuteScripts(List> scripts } } result.computeStatusIfUnknown(); - } catch (Exception e) { // FIXME little bit brutal treatment + } catch (ScriptExecutionException|JAXBException|SchemaException|RuntimeException e) { result.recordFatalError(e.getMessage(), e); LoggingUtils.logException(LOGGER, "Exception while executing script", e); } 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 1dd55f012f9..682e89e158c 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 @@ -28,6 +28,7 @@ import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.model.api.ScriptingService; import com.evolveum.midpoint.model.api.TaskService; import com.evolveum.midpoint.model.api.WorkflowService; @@ -484,8 +485,11 @@ public void run() { String oid = cacheRepositoryService.addObject(delta.getObjectToAdd(), repoOptions, result1); delta.setOid(oid); } else if (delta.isDelete()) { - PrismObject existingObject = cacheRepositoryService.getObject(delta.getObjectTypeClass(), delta.getOid(), null, result1); - securityEnforcer.authorize(ModelAuthorizationAction.DELETE.getUrl(), null, existingObject, null, null, null, result1); + if (!securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, null, null, null, null)) { + // getting the object is avoided in case of administrator's request in order to allow deleting malformed (unreadable) objects + PrismObject existingObject = cacheRepositoryService.getObject(delta.getObjectTypeClass(), delta.getOid(), null, result1); + securityEnforcer.authorize(ModelAuthorizationAction.DELETE.getUrl(), null, existingObject, null, null, null, result1); + } if (ObjectTypes.isClassManagedByProvisioning(delta.getObjectTypeClass())) { Utils.clearRequestee(task); provisioning.deleteObject(delta.getObjectTypeClass(), delta.getOid(), @@ -1857,9 +1861,15 @@ public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter } @Override - public void evaluateExpressionInBackground(JAXBElement expression, Task task, OperationResult parentResult) throws SchemaException { + public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException { scriptingExpressionEvaluator.evaluateExpressionInBackground(expression, task, parentResult); } + + @Override + public void evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException { + scriptingExpressionEvaluator.evaluateExpression(expression, task, result); + } + //endregion } \ No newline at end of file diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ActionExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ActionExecutor.java index d5faa8e55ad..60c90102a2a 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ActionExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ActionExecutor.java @@ -16,6 +16,7 @@ package com.evolveum.midpoint.model.impl.scripting; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ActionExpressionType; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/Data.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/Data.java index a6196e92d4c..bf072f44c6d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/Data.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/Data.java @@ -16,6 +16,7 @@ package com.evolveum.midpoint.model.impl.scripting; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionTaskHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionTaskHandler.java index b423248356b..af6c9841a91 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionTaskHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionTaskHandler.java @@ -16,6 +16,7 @@ package com.evolveum.midpoint.model.impl.scripting; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptingExpressionEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptingExpressionEvaluator.java index 7f24cf876d9..9c9fae0efc5 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptingExpressionEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptingExpressionEvaluator.java @@ -16,6 +16,7 @@ package com.evolveum.midpoint.model.impl.scripting; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.model.impl.scripting.expressions.SearchEvaluator; import com.evolveum.midpoint.model.impl.scripting.expressions.SelectEvaluator; import com.evolveum.midpoint.model.impl.scripting.helpers.JaxbHelper; @@ -43,16 +44,13 @@ import com.evolveum.prism.xml.ns._public.types_3.RawType; import org.apache.commons.lang.NotImplementedException; -import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.xml.bind.JAXBElement; -import javax.xml.bind.JAXBException; import javax.xml.namespace.QName; -import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -111,7 +109,7 @@ public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter ActionExpressionType action = new ActionExpressionType(); action.setType(actionName); search.setScriptingExpression(objectFactory.createAction(action)); - evaluateExpressionInBackground(objectFactory.createSearch(search), task, parentResult); + evaluateExpressionInBackground(search, task, parentResult); } /** @@ -124,7 +122,7 @@ public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter * @param parentResult * @throws SchemaException */ - public void evaluateExpressionInBackground(JAXBElement expression, Task task, OperationResult parentResult) throws SchemaException { + public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException { OperationResult result = parentResult.createSubresult(DOT_CLASS + "evaluateExpressionInBackground"); if (!task.isTransient()) { throw new IllegalStateException("Task must be transient"); @@ -133,7 +131,7 @@ public void evaluateExpressionInBackground(JAXBElement expression, Task task, OperationResult result) throws ScriptExecutionException { + + public ExecutionContext evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException { ExecutionContext context = new ExecutionContext(task); - Data output = evaluateExpression(expression, Data.createEmpty(), context, result); + Data output; + try { + output = evaluateExpression(expression, Data.createEmpty(), context, result); + } catch (RuntimeException e) { + result.recordFatalError("Couldn't execute script", e); + throw new ScriptExecutionException("Couldn't execute script: " + e.getMessage(), e); + } result.computeStatusIfUnknown(); context.setFinalOutput(output); return context; } +// public ExecutionContext evaluateExpression(JAXBElement expression, Task task, OperationResult result) throws ScriptExecutionException { +// ExecutionContext context = new ExecutionContext(task); +// Data output = evaluateExpression(expression.getValue(), Data.createEmpty(), context, result); +// result.computeStatusIfUnknown(); +// context.setFinalOutput(output); +// return context; +// } + public ExecutionContext evaluateExpression(ExecuteScriptType executeScript, Task task, OperationResult result) throws ScriptExecutionException { - return evaluateExpression(executeScript.getScriptingExpression(), task, result); + return evaluateExpression(executeScript.getScriptingExpression().getValue(), task, result); } - public ExecutionContext evaluateExpression(JAXBElement expression, OperationResult result) throws ScriptExecutionException { + public ExecutionContext evaluateExpression(ScriptingExpressionType expression, OperationResult result) throws ScriptExecutionException { Task task = taskManager.createTaskInstance(); return evaluateExpression(expression, task, result); } - public Data evaluateExpression(JAXBElement expression, Data input, ExecutionContext context, OperationResult parentResult) throws ScriptExecutionException { + public Data evaluateExpression(JAXBElement expression, Data input, ExecutionContext context, OperationResult parentResult) throws ScriptExecutionException { return evaluateExpression((ScriptingExpressionType) expression.getValue(), input, context, parentResult); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/AddExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/AddExecutor.java index b40d4a67102..d3928c4ae1e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/AddExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/AddExecutor.java @@ -18,7 +18,7 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.model.impl.scripting.helpers.OperationsHelper; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismObject; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/AssignExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/AssignExecutor.java index c77804fbd1d..7304042d371 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/AssignExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/AssignExecutor.java @@ -18,7 +18,7 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ObjectDelta; @@ -39,7 +39,6 @@ import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; -import javax.xml.bind.JAXBElement; import java.util.ArrayList; import java.util.Collection; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/BaseActionExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/BaseActionExecutor.java index ee0ec44f608..88df58b1da9 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/BaseActionExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/BaseActionExecutor.java @@ -16,12 +16,11 @@ package com.evolveum.midpoint.model.impl.scripting.actions; -import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.ModelService; import com.evolveum.midpoint.model.impl.scripting.ActionExecutor; import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.model.impl.scripting.ScriptingExpressionEvaluator; import com.evolveum.midpoint.model.impl.scripting.helpers.ExpressionHelper; import com.evolveum.midpoint.model.impl.scripting.helpers.OperationsHelper; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/DeleteExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/DeleteExecutor.java index f2173fd2e08..cdbeece8bfe 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/DeleteExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/DeleteExecutor.java @@ -18,7 +18,7 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.model.impl.scripting.helpers.OperationsHelper; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismObject; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/DiscoverConnectorsExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/DiscoverConnectorsExecutor.java index c06a5aec385..9c265222177 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/DiscoverConnectorsExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/DiscoverConnectorsExecutor.java @@ -18,16 +18,14 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.delta.ReferenceDelta; import com.evolveum.midpoint.prism.query.AndFilter; import com.evolveum.midpoint.prism.query.EqualFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; -import com.evolveum.midpoint.schema.DeltaConvertor; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.util.exception.CommunicationException; @@ -39,11 +37,8 @@ import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorHostType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ActionExpressionType; -import com.evolveum.prism.xml.ns._public.types_3.ChangeTypeType; -import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; import org.springframework.stereotype.Component; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/EnableDisableExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/EnableDisableExecutor.java index f5a3a72db28..e65a3acecdc 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/EnableDisableExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/EnableDisableExecutor.java @@ -18,7 +18,7 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.model.impl.scripting.helpers.OperationsHelper; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismObject; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/LogExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/LogExecutor.java index ac88b325eca..6591ec2bbb4 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/LogExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/LogExecutor.java @@ -18,7 +18,7 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.logging.Trace; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/ModifyExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/ModifyExecutor.java index 5cff40e1190..016d1e6b402 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/ModifyExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/ModifyExecutor.java @@ -16,10 +16,9 @@ package com.evolveum.midpoint.model.impl.scripting.actions; -import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismProperty; @@ -38,7 +37,6 @@ import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; -import javax.xml.bind.JAXBElement; /** * @author mederly diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/PurgeSchemaExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/PurgeSchemaExecutor.java index 79df9b6e74b..563c9cb5562 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/PurgeSchemaExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/PurgeSchemaExecutor.java @@ -19,7 +19,7 @@ import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismObject; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/RecomputeExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/RecomputeExecutor.java index f90b91e7616..29db41e7789 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/RecomputeExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/RecomputeExecutor.java @@ -22,7 +22,7 @@ import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/ResolveExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/ResolveExecutor.java index e16860270a8..9cedbc7209e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/ResolveExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/ResolveExecutor.java @@ -18,7 +18,7 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismProperty; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/TestResourceExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/TestResourceExecutor.java index 2677ae42ca4..2341baae4f6 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/TestResourceExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/actions/TestResourceExecutor.java @@ -18,7 +18,7 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ObjectDelta; @@ -35,7 +35,6 @@ import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorHostType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ActionExpressionType; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/expressions/SearchEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/expressions/SearchEvaluator.java index 4a53cfceb77..eafb225057a 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/expressions/SearchEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/expressions/SearchEvaluator.java @@ -18,7 +18,7 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.model.impl.scripting.helpers.ExpressionHelper; import com.evolveum.midpoint.model.impl.scripting.helpers.OperationsHelper; import com.evolveum.midpoint.prism.PrismObject; @@ -35,8 +35,8 @@ import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.SearchExpressionType; -import com.evolveum.prism.xml.ns._public.query_3.QueryType; import org.apache.commons.lang.Validate; import org.apache.commons.lang.mutable.MutableBoolean; @@ -99,7 +99,7 @@ public boolean handle(PrismObject object, OperationResult parentResult) { } JAXBElement childExpression = searchExpression.getScriptingExpression(); try { - outputData.addAllFrom(scriptingExpressionEvaluator.evaluateExpression(childExpression, Data.create(object), context, result)); + outputData.addAllFrom(scriptingExpressionEvaluator.evaluateExpression((ScriptingExpressionType) childExpression.getValue(), Data.create(object), context, result)); } catch (ScriptExecutionException e) { throw new SystemException(e); // todo think about this } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/expressions/SelectEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/expressions/SelectEvaluator.java index c1cd7152c96..6bd3b64c775 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/expressions/SelectEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/expressions/SelectEvaluator.java @@ -18,16 +18,14 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.Item; -import com.evolveum.midpoint.prism.parser.XPathHolder; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.SelectExpressionType; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import org.springframework.stereotype.Component; -import org.w3c.dom.Element; /** * @author mederly diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/ExpressionHelper.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/ExpressionHelper.java index 7c400cd5c5e..ca9d4cdd6bf 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/ExpressionHelper.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/ExpressionHelper.java @@ -18,10 +18,9 @@ import com.evolveum.midpoint.model.impl.scripting.Data; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.model.impl.scripting.ScriptingExpressionEvaluator; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ActionExpressionType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ActionParameterValueType; import com.evolveum.prism.xml.ns._public.types_3.RawType; @@ -29,8 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.xml.bind.JAXBElement; - import java.util.List; /** diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/JaxbHelper.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/JaxbHelper.java index f6d3b24ddfa..019151a498c 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/JaxbHelper.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/JaxbHelper.java @@ -16,27 +16,55 @@ package com.evolveum.midpoint.model.impl.scripting.helpers; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ActionExpressionType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ExpressionPipelineType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ExpressionSequenceType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.FilterExpressionType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ForeachExpressionType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ObjectFactory; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.SearchExpressionType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.SelectExpressionType; import org.springframework.stereotype.Component; +import javax.xml.bind.JAXBElement; +import javax.xml.namespace.QName; +import java.util.HashMap; +import java.util.Map; + /** * @author mederly */ @Component public class JaxbHelper { -// private Map, QName> elements = new HashMap<>(); -// -// private ObjectFactory objectFactory = new ObjectFactory(); -// -// public JaxbHelper() { -// elements.put(ExpressionPipelineType.class, objectFactory.createPipeline(null).getName()); -// elements.put(ExpressionSequenceType.class, objectFactory.createSequence(null).getName()); -// elements.put(ForeachExpressionType.class, objectFactory.createForeach(null).getName()); -// elements.put(SelectExpressionType.class, objectFactory.createSelect(null).getName()); -// elements.put(FilterExpressionType.class, objectFactory.createFilter(null).getName()); -// elements.put(SearchExpressionType.class, objectFactory.createSearch(null).getName()); -// elements.put(ActionExpressionType.class, objectFactory.createAction(null).getName()); -// elements.put(ConstantExpressionType.class, objectFactory.createConstant(null).getName()); -// } + private Map, QName> elements = new HashMap<>(); + + private ObjectFactory objectFactory = new ObjectFactory(); + + public JaxbHelper() { + elements.put(ExpressionPipelineType.class, objectFactory.createPipeline(null).getName()); + elements.put(ExpressionSequenceType.class, objectFactory.createSequence(null).getName()); + elements.put(ForeachExpressionType.class, objectFactory.createForeach(null).getName()); + elements.put(SelectExpressionType.class, objectFactory.createSelect(null).getName()); + elements.put(FilterExpressionType.class, objectFactory.createFilter(null).getName()); + elements.put(SearchExpressionType.class, objectFactory.createSearch(null).getName()); + elements.put(ActionExpressionType.class, objectFactory.createAction(null).getName()); + } + + /** + * Ugly hack ... sometimes we have to convert "bare" ScriptingExpressionType instance to the JAXBElement version, + * with the correct element name. + * + * @param expressionType + * @return + */ + public JAXBElement toJaxbElement(ScriptingExpressionType expressionType) { + QName qname = elements.get(expressionType.getClass()); + if (qname == null) { + throw new IllegalArgumentException("Unsupported expression type: " + expressionType.getClass()); + } + return new JAXBElement(qname, expressionType.getClass(), expressionType); + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/OperationsHelper.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/OperationsHelper.java index 4fb64cd978a..1a2dbecb6e1 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/OperationsHelper.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/helpers/OperationsHelper.java @@ -20,7 +20,7 @@ import com.evolveum.midpoint.model.api.ModelService; import com.evolveum.midpoint.model.api.PolicyViolationException; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; -import com.evolveum.midpoint.model.impl.scripting.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionException; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.GetOperationOptions; diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java index 5eb0a898030..7f8a6f68fcc 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/scripting/TestScriptingBasic.java @@ -32,10 +32,13 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ActionExpressionType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ExpressionPipelineType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ExpressionSequenceType; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ObjectFactory; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType; +import com.evolveum.midpoint.xml.ns._public.model.scripting_3.SearchExpressionType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; @@ -101,7 +104,7 @@ public void test100EmptySequence() throws Exception { ObjectFactory of = new ObjectFactory(); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(of.createSequence(sequence), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(sequence, result); // THEN assertNoOutputData(output); @@ -119,7 +122,7 @@ public void test110EmptyPipeline() throws Exception { ObjectFactory of = new ObjectFactory(); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(of.createPipeline(pipeline), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(pipeline, result); // THEN assertNoOutputData(output); @@ -133,14 +136,14 @@ public void test120Log() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test120Log"); - PrismProperty logAction = (PrismProperty) prismContext.parseAnyData(LOG_FILE); + PrismProperty logAction = (PrismProperty) prismContext.parseAnyData(LOG_FILE); LogfileTestTailer tailer = new LogfileTestTailer(); tailer.tail(); tailer.setExpecteMessage("Custom message:"); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(logAction.getAnyValue().toJaxbElement(), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(logAction.getAnyValue().getValue(), result); // THEN assertNoOutputData(output); @@ -156,10 +159,10 @@ public void test200SearchUser() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test200SearchUser"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_USERS_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_USERS_FILE); // WHEN - Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result).getFinalOutput(); + Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result).getFinalOutput(); // THEN IntegrationTestTools.display("output", output.getData()); @@ -175,10 +178,10 @@ public void test205SearchForResources() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test205SearchForResources"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_RESOURCES_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_RESOURCES_FILE); // WHEN - Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result).getFinalOutput(); + Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result).getFinalOutput(); // THEN IntegrationTestTools.display("output", output.getData()); @@ -193,10 +196,10 @@ public void test206SearchForRoles() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test206SearchForRoles"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_ROLES_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_ROLES_FILE); // WHEN - Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result).getFinalOutput(); + Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result).getFinalOutput(); // THEN IntegrationTestTools.display("output", output.getData()); @@ -211,10 +214,10 @@ public void test210SearchForShadows() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test210SearchForShadows"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_SHADOWS_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_SHADOWS_FILE); // WHEN - Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result).getFinalOutput(); + Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result).getFinalOutput(); // THEN IntegrationTestTools.display("output", output.getData()); @@ -230,10 +233,10 @@ public void test215SearchForShadowsNoFetch() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test215SearchForShadowsNoFetch"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_SHADOWS_NOFETCH_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_SHADOWS_NOFETCH_FILE); // WHEN - Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result).getFinalOutput(); + Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result).getFinalOutput(); // THEN IntegrationTestTools.display("output", output.getData()); @@ -249,10 +252,10 @@ public void test220SearchForUsersAccounts() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test220SearchForUsersAccounts"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_USERS_ACCOUNTS_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_USERS_ACCOUNTS_FILE); // WHEN - Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result).getFinalOutput(); + Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result).getFinalOutput(); // THEN IntegrationTestTools.display("output", output.getData()); @@ -268,10 +271,10 @@ public void test225SearchForUsersAccountsNoFetch() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test225SearchForUsersAccountsNoFetch"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_USERS_ACCOUNTS_NOFETCH_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(SEARCH_FOR_USERS_ACCOUNTS_NOFETCH_FILE); // WHEN - Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result).getFinalOutput(); + Data output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result).getFinalOutput(); // THEN IntegrationTestTools.display("output", output.getData()); @@ -287,10 +290,10 @@ public void test300DisableJack() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test300DisableJack"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(DISABLE_JACK_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(DISABLE_JACK_FILE); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result); // THEN assertNoOutputData(output); @@ -307,10 +310,10 @@ public void test310EnableJack() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test310EnableJack"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(ENABLE_JACK_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(ENABLE_JACK_FILE); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result); // THEN assertNoOutputData(output); @@ -327,10 +330,10 @@ public void test320DeleteAndAddJack() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test320DeleteAndAddJack"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(DELETE_AND_ADD_JACK_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(DELETE_AND_ADD_JACK_FILE); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result); // THEN assertNoOutputData(output); @@ -347,10 +350,10 @@ public void test330ModifyJack() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test330ModifyJack"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(MODIFY_JACK_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(MODIFY_JACK_FILE); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result); // THEN assertNoOutputData(output); @@ -368,10 +371,10 @@ public void test340ModifyJackBack() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test340ModifyJackBack"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(MODIFY_JACK_BACK_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(MODIFY_JACK_BACK_FILE); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result); // THEN assertNoOutputData(output); @@ -389,10 +392,10 @@ public void test350RecomputeJack() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test350RecomputeJack"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(RECOMPUTE_JACK_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(RECOMPUTE_JACK_FILE); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result); // THEN assertNoOutputData(output); @@ -409,10 +412,10 @@ public void test360AssignToJack() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test360AssignToJack"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(ASSIGN_TO_JACK_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(ASSIGN_TO_JACK_FILE); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result); // THEN assertNoOutputData(output); @@ -433,12 +436,12 @@ public void test370AssignToJackInBackground() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test370AssignToJackInBackground"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(ASSIGN_TO_JACK_2_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(ASSIGN_TO_JACK_2_FILE); // WHEN Task task = taskManager.createTaskInstance(); task.setOwner(getUser(USER_ADMINISTRATOR_OID)); - scriptingExpressionEvaluator.evaluateExpressionInBackground(expression.getAnyValue().toJaxbElement(), task, result); + scriptingExpressionEvaluator.evaluateExpressionInBackground(expression.getAnyValue().getValue(), task, result); waitForTaskFinish(task.getOid(), false); task.refresh(result); @@ -482,7 +485,7 @@ public void test400PurgeSchema() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test400PurgeSchema"); Task task = taskManager.createTaskInstance(); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(PURGE_DUMMY_BLACK_SCHEMA_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(PURGE_DUMMY_BLACK_SCHEMA_FILE); // ResourceType dummy = modelService.getObject(ResourceType.class, RESOURCE_DUMMY_BLACK_OID, null, task, result).asObjectable(); // IntegrationTestTools.display("dummy resource before purge schema", dummy.asPrismObject()); @@ -490,7 +493,7 @@ public void test400PurgeSchema() throws Exception { // IntegrationTestTools.display("schema as XML: " + DOMUtil.printDom(dummy.getSchema().getDefinition().getAny().get(0))); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result); // THEN IntegrationTestTools.display("output", output.getFinalOutput()); @@ -517,10 +520,10 @@ public void test410TestResource() throws Exception { // GIVEN OperationResult result = new OperationResult(DOT_CLASS + "test410TestResource"); - PrismProperty expression = (PrismProperty) prismContext.parseAnyData(TEST_DUMMY_RESOURCE_FILE); + PrismProperty expression = (PrismProperty) prismContext.parseAnyData(TEST_DUMMY_RESOURCE_FILE); // WHEN - ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().toJaxbElement(), result); + ExecutionContext output = scriptingExpressionEvaluator.evaluateExpression(expression.getAnyValue().getValue(), result); // THEN IntegrationTestTools.display("output", output.getFinalOutput()); diff --git a/samples/model-client-sample/src/main/java/com/evolveum/midpoint/testing/model/client/sample/Main.java b/samples/model-client-sample/src/main/java/com/evolveum/midpoint/testing/model/client/sample/Main.java index d9ce6fbbd6e..f7e68b87e14 100644 --- a/samples/model-client-sample/src/main/java/com/evolveum/midpoint/testing/model/client/sample/Main.java +++ b/samples/model-client-sample/src/main/java/com/evolveum/midpoint/testing/model/client/sample/Main.java @@ -102,7 +102,7 @@ public static void main(String[] args) { try { ModelPortType modelPort = createModelPort(args); - + SystemConfigurationType configurationType = getConfiguration(modelPort); System.out.println("Got system configuration"); System.out.println(configurationType); @@ -500,7 +500,7 @@ private static Collection listRequestableRoles(ModelPortType modelPort ObjectListType objectList = objectListHolder.value; return (Collection) objectList.getObject(); } - + private static void deleteUser(ModelPortType modelPort, String oid) throws FaultMessage { ObjectDeltaType deltaType = new ObjectDeltaType(); deltaType.setObjectType(ModelClientUtil.getTypeQName(UserType.class)); @@ -514,6 +514,20 @@ private static void deleteUser(ModelPortType modelPort, String oid) throws Fault executeOptionsType.setRaw(true); modelPort.executeChanges(deltaListType, executeOptionsType); } + + private static void deleteTask(ModelPortType modelPort, String oid) throws FaultMessage { + ObjectDeltaType deltaType = new ObjectDeltaType(); + deltaType.setObjectType(ModelClientUtil.getTypeQName(TaskType.class)); + deltaType.setChangeType(ChangeTypeType.DELETE); + deltaType.setOid(oid); + + ObjectDeltaListType deltaListType = new ObjectDeltaListType(); + deltaListType.getDelta().add(deltaType); + + ModelExecuteOptionsType executeOptionsType = new ModelExecuteOptionsType(); + executeOptionsType.setRaw(true); + modelPort.executeChanges(deltaListType, executeOptionsType); + } public static ModelPortType createModelPort(String[] args) { String endpointUrl = DEFAULT_ENDPOINT_URL; From 0c66a24cb9c7be7ed373692472ab128b626e1f17 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Tue, 29 Jul 2014 20:08:56 +0200 Subject: [PATCH 35/51] Security checking for bulk actions (MID-2006) + small gui enhancements. --- .../admin/configuration/PageBulkAction.java | 16 ++++-- .../schema/result/OperationResult.java | 8 +-- .../model/api/ModelAuthorizationAction.java | 3 +- .../model/api/ScriptExecutionResult.java | 50 +++++++++++++++++++ .../midpoint/model/api/ScriptingService.java | 8 +-- .../midpoint/model/impl/ModelWebService.java | 18 ++++--- .../impl/controller/ModelController.java | 31 ++++++------ .../impl/scripting/ExecutionContext.java | 11 ++++ .../scripting/ScriptExecutionTaskHandler.java | 16 ++++-- 9 files changed, 117 insertions(+), 44 deletions(-) create mode 100644 model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptExecutionResult.java diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java index ac5fa157435..dcc1658a1ba 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageBulkAction.java @@ -17,11 +17,14 @@ package com.evolveum.midpoint.web.page.admin.configuration; import com.evolveum.midpoint.model.api.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionResult; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.application.AuthorizationAction; @@ -119,19 +122,22 @@ private void startPerformed(AjaxRequestTarget target) { if (bulkActionDto.isAsync()) { try { getScriptingService().evaluateExpressionInBackground(expression, task, result); - } catch (SchemaException e) { - result.recordFatalError("Couldn't submit bulk action to execution because of schema exception", e); + result.recordStatus(OperationResultStatus.IN_PROGRESS, task.getName() + " has been successfully submitted to execution"); + } catch (SchemaException|SecurityViolationException e) { + result.recordFatalError("Couldn't submit bulk action to execution", e); } } else { try { - getScriptingService().evaluateExpression(expression, task, result); - } catch (ScriptExecutionException e) { + ScriptExecutionResult executionResult = getScriptingService().evaluateExpression(expression, task, result); + result.recordStatus(OperationResultStatus.SUCCESS, "Action executed. Returned " + executionResult.getDataOutput().size() + " item(s). Console and data output available via 'Export to XML' function."); + result.addReturn("console", executionResult.getConsoleOutput()); + result.addCollectionOfSerializablesAsReturn("data", executionResult.getDataOutput()); + } catch (ScriptExecutionException|SchemaException|SecurityViolationException e) { result.recordFatalError("Couldn't execute bulk action", e); } } } - result.computeStatusIfUnknown(); showResult(result); target.add(getFeedbackPanel()); } diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationResult.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationResult.java index f123f794d43..0b3e0fde1c7 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationResult.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationResult.java @@ -21,9 +21,6 @@ import javax.xml.bind.JAXBElement; -import com.evolveum.midpoint.prism.util.CloneUtil; - -import org.apache.commons.collections.map.HashedMap; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.w3c.dom.Document; @@ -37,7 +34,6 @@ import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.exception.CommonException; -import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.EntryType; @@ -674,6 +670,10 @@ public void addCollectionOfSerializablesAsParam(String paramName, Collection value) { + addReturn(name, value != null ? new ArrayList(value) : null); + } + public void addArbitraryCollectionAsParam(String paramName, Collection values) { if (values != null) { ArrayList valuesAsStrings = new ArrayList(); diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelAuthorizationAction.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelAuthorizationAction.java index 5bc81f5f67d..43711e45630 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelAuthorizationAction.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelAuthorizationAction.java @@ -30,7 +30,8 @@ public enum ModelAuthorizationAction implements DisplayableValue { DISCOVER_CONNECTORS("discoverConnectors", "Discover Connectors", "DISCOVER_CONNECTORS_HELP"), ASSIGN("assign", "Assign", "ASSIGN_HELP"), - UNASSIGN("unassign", "Unassign", "UNASSIGN_HELP"); + UNASSIGN("unassign", "Unassign", "UNASSIGN_HELP"), + EXECUTE_SCRIPT("executeScript", "Execute script", "EXECUTE_SCRIPT_HELP"); private String url; private String label; diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptExecutionResult.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptExecutionResult.java new file mode 100644 index 00000000000..aa22be4529c --- /dev/null +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptExecutionResult.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010-2014 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.api; + +import com.evolveum.midpoint.prism.Item; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Result of a script execution. + * + * @author mederly + */ +public class ScriptExecutionResult { + + private String consoleOutput; + private List dataOutput; // unmodifiable + always non-null + + public ScriptExecutionResult(String consoleOutput, List dataOutput) { + this.consoleOutput = consoleOutput; + if (dataOutput == null) { + dataOutput = new ArrayList<>(); + } + this.dataOutput = Collections.unmodifiableList(dataOutput); + } + + public String getConsoleOutput() { + return consoleOutput; + } + + public List getDataOutput() { + return dataOutput; + } +} diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptingService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptingService.java index 994b1ebaa4a..b4af75b8e4a 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptingService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ScriptingService.java @@ -20,9 +20,9 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.xml.ns._public.model.scripting_3.ScriptingExpressionType; -import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; /** @@ -46,7 +46,7 @@ public interface ScriptingService { * * TODO consider removing this method (it was meant as a simplified version of the method below) */ - public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException; + public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException; /** * Asynchronously executes any scripting expression. @@ -59,7 +59,7 @@ public interface ScriptingService { * @param parentResult * @throws SchemaException */ - public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException; + public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException; /** * Synchronously executes any scripting expression (with no input data). @@ -72,5 +72,5 @@ public interface ScriptingService { * TODO return ExecutionContext (requires moving the context to model api) */ - public void evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException; + public ScriptExecutionResult evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException, SchemaException, SecurityViolationException; } \ No newline at end of file diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java index 6134d4c3dc2..7ba692fe9ef 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelWebService.java @@ -17,6 +17,8 @@ import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.ModelPort; +import com.evolveum.midpoint.model.api.ScriptExecutionResult; +import com.evolveum.midpoint.model.api.ScriptingService; import com.evolveum.midpoint.model.common.util.AbstractModelWebService; import com.evolveum.midpoint.model.impl.controller.ModelController; import com.evolveum.midpoint.model.impl.scripting.Data; @@ -108,7 +110,7 @@ public class ModelWebService extends AbstractModelWebService implements ModelPor private ModelController modelController; @Autowired - private ScriptingExpressionEvaluator scriptingExpressionEvaluator; + private ScriptingService scriptingService; @Override public void getObject(QName objectType, String oid, SelectorQualifiedGetOptionsType optionsType, @@ -273,22 +275,22 @@ private ExecuteScriptsResponseType doExecuteScripts(List> scripts try { for (JAXBElement script : scriptsToExecute) { - ExecutionContext outputContext = scriptingExpressionEvaluator.evaluateExpression((ScriptingExpressionType) script.getValue(), task, result); + ScriptExecutionResult executionResult = scriptingService.evaluateExpression((ScriptingExpressionType) script.getValue(), task, result); SingleScriptOutputType output = new SingleScriptOutputType(); outputs.getOutput().add(output); - output.setTextOutput(outputContext.getConsoleOutput()); + output.setTextOutput(executionResult.getConsoleOutput()); if (options == null || options.getOutputFormat() == null || options.getOutputFormat() == OutputFormatType.XML) { - output.setXmlData(prepareXmlData(outputContext.getFinalOutput())); + output.setXmlData(prepareXmlData(executionResult.getDataOutput())); } else { // temporarily we send serialized XML in the case of MSL output - ItemListType jaxbOutput = prepareXmlData(outputContext.getFinalOutput()); + ItemListType jaxbOutput = prepareXmlData(executionResult.getDataOutput()); output.setMslData(prismContext.serializeAnyData(jaxbOutput, SchemaConstants.C_VALUE, PrismContext.LANG_XML)); } } result.computeStatusIfUnknown(); - } catch (ScriptExecutionException|JAXBException|SchemaException|RuntimeException e) { + } catch (ScriptExecutionException|JAXBException|SchemaException|RuntimeException|SecurityViolationException e) { result.recordFatalError(e.getMessage(), e); LoggingUtils.logException(LOGGER, "Exception while executing script", e); } @@ -297,10 +299,10 @@ private ExecuteScriptsResponseType doExecuteScripts(List> scripts return response; } - private ItemListType prepareXmlData(Data output) throws JAXBException, SchemaException { + private ItemListType prepareXmlData(List output) throws JAXBException, SchemaException { ItemListType itemListType = new ItemListType(); if (output != null) { - for (Item item : output.getData()) { + for (Item item : output) { RawType rawType = prismContext.toRawType(item); itemListType.getItem().add(rawType); } 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 682e89e158c..c3fffbb6030 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 @@ -22,17 +22,17 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; -import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; import com.evolveum.midpoint.model.api.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionResult; import com.evolveum.midpoint.model.api.ScriptingService; import com.evolveum.midpoint.model.api.TaskService; import com.evolveum.midpoint.model.api.WorkflowService; import com.evolveum.midpoint.model.api.hooks.ReadHook; +import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; import com.evolveum.midpoint.model.impl.scripting.ScriptingExpressionEvaluator; import com.evolveum.midpoint.prism.parser.XNodeSerializer; import com.evolveum.midpoint.prism.polystring.PolyString; @@ -44,13 +44,8 @@ import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; -import org.apache.cxf.phase.Phase; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import com.evolveum.midpoint.audit.api.AuditEventRecord; @@ -61,7 +56,6 @@ import com.evolveum.midpoint.common.crypto.CryptoUtil; import com.evolveum.midpoint.common.refinery.LayerRefinedAttributeDefinition; import com.evolveum.midpoint.common.refinery.LayerRefinedObjectClassDefinition; -import com.evolveum.midpoint.common.refinery.LayerRefinedResourceSchema; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.RefinedResourceSchema; import com.evolveum.midpoint.model.api.ModelAuthorizationAction; @@ -117,18 +111,14 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultRunner; import com.evolveum.midpoint.schema.result.OperationResultStatus; -import com.evolveum.midpoint.schema.util.ShadowUtil; -import com.evolveum.midpoint.security.api.Authorization; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.security.api.ObjectSecurityConstraints; -import com.evolveum.midpoint.security.api.OwnerResolver; import com.evolveum.midpoint.security.api.SecurityEnforcer; import com.evolveum.midpoint.security.api.UserProfileService; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.DisplayableValue; -import com.evolveum.midpoint.util.exception.CommonException; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; @@ -145,7 +135,6 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorHostType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.LayerType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectSynchronizationType; @@ -1856,18 +1845,26 @@ public void releaseWorkItem(String workItemId, OperationResult parentResult) { //region Scripting (bulk actions) @Override - public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException { + public void evaluateExpressionInBackground(QName objectType, ObjectFilter filter, String actionName, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException { + checkScriptingAuthorization(parentResult); scriptingExpressionEvaluator.evaluateExpressionInBackground(objectType, filter, actionName, task, parentResult); } @Override - public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException { + public void evaluateExpressionInBackground(ScriptingExpressionType expression, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException { + checkScriptingAuthorization(parentResult); scriptingExpressionEvaluator.evaluateExpressionInBackground(expression, task, parentResult); } @Override - public void evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException { - scriptingExpressionEvaluator.evaluateExpression(expression, task, result); + public ScriptExecutionResult evaluateExpression(ScriptingExpressionType expression, Task task, OperationResult result) throws ScriptExecutionException, SchemaException, SecurityViolationException { + checkScriptingAuthorization(result); + ExecutionContext executionContext = scriptingExpressionEvaluator.evaluateExpression(expression, task, result); + return executionContext.toExecutionResult(); + } + + private void checkScriptingAuthorization(OperationResult parentResult) throws SchemaException, SecurityViolationException { + securityEnforcer.authorize(ModelAuthorizationAction.EXECUTE_SCRIPT.getUrl(), null, null, null, null, null, parentResult); } //endregion diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ExecutionContext.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ExecutionContext.java index f567e7921ba..d4cd0024912 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ExecutionContext.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ExecutionContext.java @@ -16,12 +16,14 @@ package com.evolveum.midpoint.model.impl.scripting; +import com.evolveum.midpoint.model.api.ScriptExecutionResult; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -80,4 +82,13 @@ public Data getFinalOutput() { public void setFinalOutput(Data finalOutput) { this.finalOutput = finalOutput; } + + public ScriptExecutionResult toExecutionResult() { + List items = null; + if (getFinalOutput() != null) { + items = getFinalOutput().getData(); + } + ScriptExecutionResult result = new ScriptExecutionResult(getConsoleOutput(), items); + return result; + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionTaskHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionTaskHandler.java index af6c9841a91..80d5501e971 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionTaskHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/scripting/ScriptExecutionTaskHandler.java @@ -17,6 +17,8 @@ package com.evolveum.midpoint.model.impl.scripting; import com.evolveum.midpoint.model.api.ScriptExecutionException; +import com.evolveum.midpoint.model.api.ScriptExecutionResult; +import com.evolveum.midpoint.model.api.ScriptingService; import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; @@ -25,6 +27,8 @@ import com.evolveum.midpoint.task.api.TaskHandler; import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.task.api.TaskRunResult; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; @@ -52,7 +56,7 @@ public class ScriptExecutionTaskHandler implements TaskHandler { private TaskManager taskManager; @Autowired - private ScriptingExpressionEvaluator scriptingExpressionEvaluator; + private ScriptingService scriptingService; @Override public TaskRunResult run(Task task) { @@ -61,16 +65,18 @@ public TaskRunResult run(Task task) { TaskRunResult runResult = new TaskRunResult(); PrismProperty executeScriptProperty = task.getExtensionProperty(SchemaConstants.SE_EXECUTE_SCRIPT); - if (executeScriptProperty == null) { + if (executeScriptProperty == null || executeScriptProperty.getValue().getValue() == null || + executeScriptProperty.getValue().getValue().getScriptingExpression() == null) { throw new IllegalStateException("There's no script to be run in task " + task + " (property " + SchemaConstants.SE_EXECUTE_SCRIPT + ")"); } try { - ExecutionContext resultingContext = scriptingExpressionEvaluator.evaluateExpression(executeScriptProperty.getRealValue(), task, result); - LOGGER.debug("Execution result:\n", resultingContext.getConsoleOutput()); + ScriptExecutionResult executionResult = scriptingService.evaluateExpression(executeScriptProperty.getValue().getValue().getScriptingExpression().getValue(), task, result); + LOGGER.debug("Execution output: {} item(s)", executionResult.getDataOutput().size()); + LOGGER.debug("Execution result:\n", executionResult.getConsoleOutput()); result.computeStatus(); runResult.setRunResultStatus(TaskRunResult.TaskRunResultStatus.FINISHED); - } catch (ScriptExecutionException e) { + } catch (ScriptExecutionException|SecurityViolationException|SchemaException e) { result.recordFatalError("Couldn't execute script: " + e.getMessage(), e); LoggingUtils.logException(LOGGER, "Couldn't execute script", e); runResult.setRunResultStatus(TaskRunResult.TaskRunResultStatus.PERMANENT_ERROR); From be1f933e3fcc13941d1af4912295b40b03b6c026 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 30 Jul 2014 09:36:31 +0200 Subject: [PATCH 36/51] Reworking assignment mapping code. --- .../midpoint/prism/delta/ContainerDelta.java | 9 +- .../midpoint/prism/delta/ItemDelta.java | 124 ++++++---- .../midpoint/prism/delta/PropertyDelta.java | 24 +- .../midpoint/prism/delta/ReferenceDelta.java | 10 +- .../schema/processor/SimpleDelta.java | 72 ------ .../common/expression/ItemDeltaItem.java | 97 +++++++- .../model/impl/lens/AssignmentEvaluator.java | 90 ++++--- .../model/impl/lens/AssignmentPath.java | 10 +- .../impl/lens/AssignmentPathSegment.java | 39 +-- .../impl/lens/AssignmentPathVariables.java | 43 ++-- .../model/impl/lens/Construction.java | 22 +- .../model/impl/lens/EvaluatedAssignment.java | 20 +- .../midpoint/model/impl/lens/LensUtil.java | 99 ++++++-- .../lens/projector/ActivationProcessor.java | 2 +- .../lens/projector/AssignmentProcessor.java | 72 +++--- .../projector/PasswordPolicyProcessor.java | 10 +- .../impl/security/UserProfileServiceImpl.java | 10 +- .../model/impl/lens/AbstractLensTest.java | 4 + .../impl/lens/TestAssignmentEvaluator.java | 226 ++++++++++++++++-- .../model/impl/lens/TestProjector.java | 54 +++++ .../lens/assignment-direct-expression.xml | 39 +++ .../src/test/resources/lens/role-mutinier.xml | 48 ++++ .../src/test/resources/lens/role-pirate.xml | 2 +- .../src/test/resources/logback-test.xml | 2 +- .../midpoint/model/intest/TestRbac.java | 90 +++++++ .../src/test/resources/logback-test.xml | 2 +- .../src/test/resources/rbac/role-cleric.xml | 43 ++++ .../provisioning/impl/ResourceManager.java | 6 +- .../impl/ResourceObjectConverter.java | 12 +- .../provisioning/impl/ShadowCache.java | 2 +- .../ucf/impl/ConnectorInstanceIcfImpl.java | 4 +- 31 files changed, 933 insertions(+), 354 deletions(-) delete mode 100644 infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SimpleDelta.java create mode 100644 model/model-impl/src/test/resources/lens/assignment-direct-expression.xml create mode 100644 model/model-impl/src/test/resources/lens/role-mutinier.xml create mode 100644 model/model-intest/src/test/resources/rbac/role-cleric.xml diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ContainerDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ContainerDelta.java index 8f2741f31bc..7473ea8172b 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ContainerDelta.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ContainerDelta.java @@ -145,13 +145,10 @@ public Class getCompileTimeClass() { } @Override - public void applyTo(Item item) throws SchemaException { - if (!(item instanceof PrismContainer)) { - throw new SchemaException("Cannot apply container delta "+this+" to item "+item+" of type "+item.getClass()); - } - super.applyTo(item); + protected boolean isApplicableToType(Item item) { + return item instanceof PrismContainer; } - + public ItemDelta findItemDelta(ItemPath path) { if (path.isEmpty()) { return this; diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java index 522ae7fe575..5f9e35a3390 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java @@ -34,6 +34,7 @@ import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.prism.PrismValue; import com.evolveum.midpoint.prism.Visitable; import com.evolveum.midpoint.prism.Visitor; @@ -49,6 +50,7 @@ import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; + import org.apache.commons.lang.Validate; /** @@ -907,19 +909,6 @@ public void simplify() { valuesToDelete = null; } } - - /** - * Apply this delta (path) to a property container. - */ - public void applyTo(PrismContainer propertyContainer) throws SchemaException { - ItemPath itemPath = getPath(); - Item item = propertyContainer.findOrCreateItem(itemPath, getItemClass(), getDefinition()); - if (item == null) { - throw new IllegalStateException("Cannot apply delta because cannot find item "+itemPath+" in "+propertyContainer); - } - applyTo(item); - cleanupAllTheWayUp(item); - } private void cleanupAllTheWayUp(Item item) { if (item.isEmpty()) { @@ -947,30 +936,44 @@ public static void applyTo(Collection deltas, PrismContaine } } - /** - * Apply this delta (path) to a property container. - */ - public void applyTo(PrismContainerValue propertyContainerVal) throws SchemaException { - ItemPath itemPath = getPath(); - Item item = propertyContainerVal.findOrCreateItem(itemPath, getItemClass(), getDefinition()); - if (item == null) { - throw new IllegalStateException("Cannot apply delta because cannot find item "+itemPath+" in "+propertyContainerVal); - } - applyTo(item); - if (item.isEmpty()) { - propertyContainerVal.remove(item); + public void applyTo(Item item) throws SchemaException { + ItemPath itemPath = item.getPath(); + ItemPath deltaPath = getPath(); + CompareResult compareComplex = itemPath.compareComplex(deltaPath); + if (compareComplex == CompareResult.EQUIVALENT) { + applyToMatchingPath(item); + cleanupAllTheWayUp(item); + } else if (compareComplex == CompareResult.SUBPATH) { + if (item instanceof PrismContainer) { + PrismContainer container = (PrismContainer)item; + ItemPath remainderPath = deltaPath.remainder(itemPath); + Item subItem = container.findOrCreateItem(remainderPath, getItemClass()); + applyToMatchingPath(subItem); + } else { + throw new SchemaException("Cannot apply delta "+this+" to "+item+" as delta path is below the item path and the item is not a container"); + } + } else if (compareComplex == CompareResult.SUPERPATH) { + throw new SchemaException("Cannot apply delta "+this+" to "+item+" as delta path is above the item path"); + } else if (compareComplex == CompareResult.NO_RELATION) { + throw new SchemaException("Cannot apply delta "+this+" to "+item+" as paths do not match"); } } - + /** - * Apply this delta (path) to a property. + * Applies delta to item were path of the delta and path of the item matches (skips path checks). */ - public void applyTo(Item item) throws SchemaException { + public void applyToMatchingPath(Item item) throws SchemaException { if (item.getDefinition() == null && getDefinition() != null){ item.applyDefinition(getDefinition()); } + if (!getItemClass().isAssignableFrom(item.getClass())) { + throw new SchemaException("Cannot apply delta "+this+" to "+item+" because the deltas is applicable only to "+getItemClass().getSimpleName()); + } if (valuesToReplace != null) { item.replaceAll(PrismValue.cloneCollection(valuesToReplace)); + // Application of delta might have removed values therefore leaving empty items. + // Those needs to be cleaned-up (removed) as empty item is not a legal state. + cleanupAllTheWayUp(item); return; } if (valuesToAdd != null) { @@ -987,9 +990,24 @@ public void applyTo(Item item) throws SchemaException { if (valuesToDelete != null) { item.removeAll(valuesToDelete); } - + // Application of delta might have removed values therefore leaving empty items. + // Those needs to be cleaned-up (removed) as empty item is not a legal state. + cleanupAllTheWayUp(item); } + public boolean isApplicableTo(Item item) { + if (item == null) { + return false; + } + if (!isApplicableToType(item)) { + return false; + } + // TODO: maybe check path? + return true; + } + + protected abstract boolean isApplicableToType(Item item); + public static void accept(Collection modifications, Visitor visitor, ItemPath path, boolean recursive) { for (ItemDelta modification: modifications) { @@ -1003,19 +1021,6 @@ public static void accept(Collection modifications, Visitor } } - - public I computeChangedItem(I oldItem) throws SchemaException { - if (isEmpty()) { - return oldItem; - } - if (oldItem == null) { - // Instantiate empty item - oldItem = (I) getDefinition().instantiate(); - } - applyTo(oldItem); - return oldItem; - } - /** * Returns the "new" state of the property - the state that would be after * the delta is applied. @@ -1032,17 +1037,36 @@ public Item getItemNew(Item itemOld) throws SchemaException { if (definition == null) { throw new IllegalStateException("No definition in "+this); } + Item itemNew; if (itemOld == null) { if (isEmpty()) { return null; } - itemOld = definition.instantiate(getElementName()); + itemNew = definition.instantiate(getElementName()); + } else { + itemNew = itemOld.clone(); } - Item itemNew = itemOld.clone(); applyTo(itemNew); return itemNew; } + public Item getItemNewMatchingPath(Item itemOld) throws SchemaException { + if (definition == null) { + throw new IllegalStateException("No definition in "+this); + } + Item itemNew; + if (itemOld == null) { + if (isEmpty()) { + return null; + } + itemNew = definition.instantiate(getElementName()); + } else { + itemNew = itemOld.clone(); + } + applyToMatchingPath(itemNew); + return itemNew; + } + /** * Returns true if the other delta is a complete subset of this delta. * I.e. if all the statements of the other delta are already contained @@ -1101,6 +1125,18 @@ private Collection cloneSet(ItemDelta clone, Collection thisSet) { } return clonedSet; } + + public static > Collection cloneCollection(Collection orig) { + if (orig == null) { + return null; + } + Collection clone = new ArrayList<>(orig.size()); + for (D delta: orig) { + clone.add((D)delta.clone()); + } + return clone; + } + @Deprecated public static PrismValueDeltaSetTriple toDeltaSetTriple(Item item, ItemDelta delta, diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/PropertyDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/PropertyDelta.java index 65fb196a8df..efae32351f2 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/PropertyDelta.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/PropertyDelta.java @@ -123,20 +123,8 @@ public

P instantiateEmptyProperty() { } @Override - public void applyTo(Item item) throws SchemaException { - if (item instanceof PrismProperty) { - super.applyTo(item); - } else if (item instanceof PrismContainer) { - PrismContainer container = (PrismContainer)item; - ItemPath remainderPath = getPath().remainder(item.getPath()); - PrismProperty property = container.findProperty(remainderPath); - if (property == null) { - throw new SchemaException("Cannot apply property delta "+this+" to item "+item+" because there is no property with path "+remainderPath); - } - applyTo(property); - } else { - throw new SchemaException("Cannot apply property delta "+this+" to item "+item+" of type "+item.getClass()); - } + protected boolean isApplicableToType(Item item) { + return item instanceof PrismProperty; } @Override @@ -265,16 +253,16 @@ public boolean isRealValueToDelete(PrismPropertyValue value) { * Returns the "new" state of the property - the state that would be after the delta * is applied. */ - public PrismProperty getPropertyNew() throws SchemaException { - return (PrismProperty) super.getItemNew(); + public PrismProperty getPropertyNewMatchingPath() throws SchemaException { + return (PrismProperty) super.getItemNewMatchingPath(null); } /** * Returns the "new" state of the property - the state that would be after the delta * is applied. */ - public PrismProperty getPropertyNew(PrismProperty propertyOld) throws SchemaException { - return (PrismProperty) super.getItemNew(propertyOld); + public PrismProperty getPropertyNewMatchingPath(PrismProperty propertyOld) throws SchemaException { + return (PrismProperty) super.getItemNewMatchingPath(propertyOld); } @Override diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ReferenceDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ReferenceDelta.java index 0fa4e113d90..21842edc88b 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ReferenceDelta.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ReferenceDelta.java @@ -23,6 +23,7 @@ import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.Objectable; +import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismObjectDefinition; @@ -75,13 +76,10 @@ public void applyDefinition(ItemDefinition definition) throws SchemaException { } super.applyDefinition(definition); } - + @Override - public void applyTo(Item item) throws SchemaException { - if (!(item instanceof PrismReference)) { - throw new SchemaException("Cannot apply reference delta "+this+" to item "+item+" of type "+item.getClass()); - } - super.applyTo(item); + protected boolean isApplicableToType(Item item) { + return item instanceof PrismReference; } @Override diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SimpleDelta.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SimpleDelta.java deleted file mode 100644 index 884aef44025..00000000000 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SimpleDelta.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.schema.processor; - -import java.util.ArrayList; -import java.util.Collection; - -/** - * @author semancik - * - */ -public class SimpleDelta { - - private DeltaType type; - private Collection change; - - public SimpleDelta() { - super(); - // Construct list so it will maintain ordering - // but we don't guarantee that. This is more-or-less just - // for esthetic reasons (e.g. debug output). - change = new ArrayList(); - } - - public SimpleDelta(DeltaType type) { - super(); - // Construct list so it will maintain ordering - // but we don't guarantee that. This is more-or-less just - // for esthetic reasons (e.g. debug output). - change = new ArrayList(); - this.type = type; - } - - public DeltaType getType() { - return type; - } - - public void setType(DeltaType type) { - this.type = type; - } - - public Collection getChange() { - return change; - } - - public void add(T object) { - change.add(object); - } - - @Override - public String toString() { - return "Delta(" + type + ",[" + change + "])"; - } - - public enum DeltaType { - ADD, DELETE; - } - -} diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java index 3163ebc05c7..4fc39b69822 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java @@ -49,9 +49,11 @@ public class ItemDeltaItem { ItemPath resolvePath = ItemPath.EMPTY_PATH; ItemPath residualPath = null; - public ItemDeltaItem() { - - } + // The deltas in sub-items. E.g. if this object represents "ContainerDeltaContainer" + // this property contains property deltas that may exist inside the container. + Collection> subItemDeltas; + + public ItemDeltaItem() { } public ItemDeltaItem(Item itemOld, ItemDelta delta, Item itemNew) { super(); @@ -121,8 +123,16 @@ public void setResolvePath(ItemPath resolvePath) { this.resolvePath = resolvePath; } + public Collection> getSubItemDeltas() { + return subItemDeltas; + } + + public void setSubItemDeltas(Collection> subItemDeltas) { + this.subItemDeltas = subItemDeltas; + } + public boolean isNull() { - return itemOld == null && itemNew == null && delta == null; + return itemOld == null && itemNew == null && delta == null && subItemDeltas == null; } public QName getElementName() { @@ -149,10 +159,18 @@ public ItemDefinition getDefinition() { public void recompute() throws SchemaException { if (delta != null) { - itemNew = delta.getItemNew(itemOld); + itemNew = delta.getItemNewMatchingPath(itemOld); } else { itemNew = itemOld; } + if (subItemDeltas != null && !subItemDeltas.isEmpty()) { + if (itemNew == null) { + throw new SchemaException("Cannot apply subitem delta to null new item"); + } + for (ItemDelta subItemDelta: subItemDeltas) { + itemNew = (Item) subItemDelta.getItemNew((Item) itemNew); + } + } } public ItemDeltaItem findIdi(ItemPath path) { @@ -179,20 +197,46 @@ public ItemDeltaItem findIdi(ItemPath path) { } } } - ItemDelta subItemDelta= null; + ItemDelta subDelta= null; if (delta != null) { if (delta instanceof ContainerDelta) { - subItemDelta = (ItemDelta) ((ContainerDelta)delta).findItemDelta(path); + subDelta = (ItemDelta) ((ContainerDelta)delta).findItemDelta(path); } else { CompareResult compareComplex = delta.getPath().compareComplex(newResolvePath); if (compareComplex == CompareResult.EQUIVALENT || compareComplex == CompareResult.SUBPATH) { - subItemDelta = (ItemDelta) delta; + subDelta = (ItemDelta) delta; } } } - ItemDeltaItem subIdi = new ItemDeltaItem(subItemOld, subItemDelta, subItemNew); + ItemDeltaItem subIdi = new ItemDeltaItem(subItemOld, subDelta, subItemNew); subIdi.setResidualPath(subResidualPath); subIdi.resolvePath = newResolvePath; + + if (subItemDeltas != null) { + Item subAnyItem = subIdi.getAnyItem(); + Collection> subSubItemDeltas = new ArrayList<>(); + for (ItemDelta subItemDelta: subItemDeltas) { + CompareResult compareComplex = subItemDelta.getPath().compareComplex(subAnyItem.getPath()); + if (compareComplex == CompareResult.EQUIVALENT || compareComplex == CompareResult.SUBPATH) { + subSubItemDeltas.add(subItemDelta); + } + } + if (!subSubItemDeltas.isEmpty()) { + // Niceness optimization + if (subDelta == null && subSubItemDeltas.size() == 1) { + ItemDelta subSubItemDelta = subSubItemDeltas.iterator().next(); + if (subSubItemDelta.isApplicableTo(subAnyItem)) { + subDelta = (ItemDelta) subSubItemDelta; + subIdi.setDelta(subDelta); + } else { + subIdi.setSubItemDeltas(subSubItemDeltas); + } + } else { + subIdi.setSubItemDeltas(subSubItemDeltas); + } + } + } + return subIdi; } @@ -295,6 +339,41 @@ private Collection> resolveStructuredDeltaSet(Collecti } return outputSet; } + + public void applyDefinition(ItemDefinition def, boolean force) throws SchemaException { + if (itemNew != null) { + itemNew.applyDefinition(def, force); + } + if (itemOld != null) { + itemOld.applyDefinition(def, force); + } + if (delta != null) { + delta.applyDefinition(def, force); + } + } + + public ItemDeltaItem clone() { + ItemDeltaItem clone = new ItemDeltaItem<>(); + copyValues(clone); + return clone; + } + + protected void copyValues(ItemDeltaItem clone) { + if (this.itemNew != null) { + clone.itemNew = this.itemNew.clone(); + } + if (this.delta != null) { + clone.delta = this.delta.clone(); + } + if (this.itemOld != null) { + clone.itemOld = this.itemOld.clone(); + } + clone.residualPath = this.residualPath; + clone.resolvePath = this.resolvePath; + if (this.subItemDeltas != null) { + clone.subItemDeltas = ItemDelta.cloneCollection(this.subItemDeltas); + } + } @Override public int hashCode() { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java index 3656330a581..8745b881073 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java @@ -16,6 +16,7 @@ package com.evolveum.midpoint.model.impl.lens; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import javax.xml.datatype.XMLGregorianCalendar; @@ -23,6 +24,7 @@ import com.evolveum.midpoint.common.ActivationComputer; import com.evolveum.midpoint.model.api.PolicyViolationException; +import com.evolveum.midpoint.model.common.expression.ItemDeltaItem; import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject; import com.evolveum.midpoint.model.common.mapping.Mapping; import com.evolveum.midpoint.model.common.mapping.MappingFactory; @@ -35,9 +37,9 @@ import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.OriginType; import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.schema.processor.SimpleDelta; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ObjectResolver; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; @@ -171,33 +173,21 @@ public PrismObject getSystemConfiguration() { public void setSystemConfiguration(PrismObject systemConfiguration) { this.systemConfiguration = systemConfiguration; } - - public SimpleDelta evaluate(SimpleDelta assignmentTypeDelta, ObjectType source, String sourceDescription, - Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { - SimpleDelta delta = new SimpleDelta(); - delta.setType(assignmentTypeDelta.getType()); - for (AssignmentType assignmentType : assignmentTypeDelta.getChange()) { - assertSource(source, assignmentType); - EvaluatedAssignment assignment = evaluate(assignmentType, source, sourceDescription, task, result); - delta.getChange().add(assignment); - } - return delta; - } - public EvaluatedAssignment evaluate(AssignmentType assignmentType, ObjectType source, String sourceDescription, - Task task, OperationResult result) + public EvaluatedAssignment evaluate(ItemDeltaItem> assignmentIdi, + boolean evaluateOld, ObjectType source, String sourceDescription, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { - assertSource(source, assignmentType); - EvaluatedAssignment evalAssignment = new EvaluatedAssignment(); - evalAssignment.setAssignmentType(assignmentType); + assertSource(source, assignmentIdi); + EvaluatedAssignment evalAssignment = new EvaluatedAssignment<>(); + evalAssignment.setAssignmentIdi(assignmentIdi); AssignmentPath assignmentPath = new AssignmentPath(); - AssignmentPathSegment assignmentPathSegment = new AssignmentPathSegment(assignmentType, null); + AssignmentPathSegment assignmentPathSegment = new AssignmentPathSegment(assignmentIdi, null); assignmentPathSegment.setSource(source); assignmentPathSegment.setEvaluationOrder(1); assignmentPathSegment.setEvaluateConstructions(true); assignmentPathSegment.setValidityOverride(true); - evaluateAssignment(evalAssignment, assignmentPathSegment, source, sourceDescription, assignmentPath, task, result); + evaluateAssignment(evalAssignment, assignmentPathSegment, evaluateOld, source, sourceDescription, assignmentPath, task, result); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Assignment evaluation finished:\n{}", evalAssignment.debugDump()); @@ -206,13 +196,15 @@ public EvaluatedAssignment evaluate(AssignmentType assignmentType, ObjectType so return evalAssignment; } - private void evaluateAssignment(EvaluatedAssignment evalAssignment, AssignmentPathSegment assignmentPathSegment, ObjectType source, String sourceDescription, + private void evaluateAssignment(EvaluatedAssignment evalAssignment, AssignmentPathSegment assignmentPathSegment, + boolean evaluateOld, ObjectType source, String sourceDescription, AssignmentPath assignmentPath, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { assertSource(source, evalAssignment); LOGGER.trace("Evaluate assignment {} (eval constr: {})", assignmentPath, assignmentPathSegment.isEvaluateConstructions()); - AssignmentType assignmentType = assignmentPathSegment.getAssignmentType(); + ItemDeltaItem> assignmentIdi = assignmentPathSegment.getAssignmentIdi(); + AssignmentType assignmentType = LensUtil.getAssignmentType(assignmentIdi, evaluateOld); checkSchema(assignmentType, sourceDescription); @@ -243,20 +235,20 @@ private void evaluateAssignment(EvaluatedAssignment evalAssignment, AssignmentPa if (assignmentType.getConstruction() != null) { if (evaluateConstructions && assignmentPathSegment.isEvaluateConstructions()) { - prepareConstructionEvaluation(evalAssignment, assignmentPathSegment, source, sourceDescription, + prepareConstructionEvaluation(evalAssignment, assignmentPathSegment, evaluateOld, source, sourceDescription, assignmentPath, assignmentPathSegment.getOrderOneObject(), task, result); } } else if (assignmentType.getFocusMappings() != null) { if (evaluateConstructions && assignmentPathSegment.isEvaluateConstructions()) { - evaluateFocusMappings(evalAssignment, assignmentPathSegment, source, sourceDescription, + evaluateFocusMappings(evalAssignment, assignmentPathSegment, evaluateOld, source, sourceDescription, assignmentPath, assignmentPathSegment.getOrderOneObject(), task, result); } } else if (target != null) { - evaluateTarget(evalAssignment, assignmentPathSegment, target, source, assignmentType.getTargetRef().getRelation(), sourceDescription, + evaluateTarget(evalAssignment, assignmentPathSegment, evaluateOld, target, source, assignmentType.getTargetRef().getRelation(), sourceDescription, assignmentPath, task, result); } else { @@ -274,20 +266,20 @@ private void evaluateAssignment(EvaluatedAssignment evalAssignment, AssignmentPa assignmentPath.remove(assignmentPathSegment); } - private void prepareConstructionEvaluation(EvaluatedAssignment evaluatedAssignment, AssignmentPathSegment assignmentPathSegment, ObjectType source, String sourceDescription, + private void prepareConstructionEvaluation(EvaluatedAssignment evaluatedAssignment, AssignmentPathSegment assignmentPathSegment, + boolean evaluateOld, ObjectType source, String sourceDescription, AssignmentPath assignmentPath, ObjectType orderOneObject, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException { assertSource(source, evaluatedAssignment); - - AssignmentType assignmentType = assignmentPathSegment.getAssignmentType(); - ConstructionType constructionType = assignmentType.getConstruction(); + AssignmentType assignmentTypeNew = LensUtil.getAssignmentType(assignmentPathSegment.getAssignmentIdi(), evaluateOld); + ConstructionType constructionType = assignmentTypeNew.getConstruction(); LOGGER.trace("Preparing construction '{}' in {}", constructionType.getDescription(), source); Construction construction = new Construction(constructionType, source); // We have to clone here as the path is constantly changing during evaluation construction.setAssignmentPath(assignmentPath.clone()); - construction.setUserOdo(focusOdo); + construction.setFocusOdo(focusOdo); construction.setLensContext(lensContext); construction.setObjectResolver(objectResolver); construction.setPrismContext(prismContext); @@ -301,13 +293,13 @@ private void prepareConstructionEvaluation(EvaluatedAssignment evaluatedAssignme evaluatedAssignment.addConstruction(construction); } - private void evaluateFocusMappings(EvaluatedAssignment evaluatedAssignment, AssignmentPathSegment assignmentPathSegment, ObjectType source, String sourceDescription, + private void evaluateFocusMappings(EvaluatedAssignment evaluatedAssignment, AssignmentPathSegment assignmentPathSegment, + boolean evaluateOld, ObjectType source, String sourceDescription, AssignmentPath assignmentPath, ObjectType orderOneObject, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException { assertSource(source, evaluatedAssignment); - - AssignmentType assignmentType = assignmentPathSegment.getAssignmentType(); - MappingsType mappingsType = assignmentType.getFocusMappings(); + AssignmentType assignmentTypeNew = LensUtil.getAssignmentType(assignmentPathSegment.getAssignmentIdi(), evaluateOld); + MappingsType mappingsType = assignmentTypeNew.getFocusMappings(); LOGGER.trace("Evaluate focus mappings '{}' in {} ({} mappings)", new Object[]{mappingsType.getDescription(), source, mappingsType.getMapping().size()}); @@ -359,14 +351,14 @@ private PrismObject resolveTarget(AssignmentType assignmentType, ObjectType s } - private void evaluateTarget(EvaluatedAssignment assignment, AssignmentPathSegment assignmentPathSegment, PrismObject target, - ObjectType source, QName relation, String sourceDescription, + private void evaluateTarget(EvaluatedAssignment assignment, AssignmentPathSegment assignmentPathSegment, + boolean evaluateOld, PrismObject target, ObjectType source, QName relation, String sourceDescription, AssignmentPath assignmentPath, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { assertSource(source, assignment); ObjectType targetType = (ObjectType) target.asObjectable(); assignmentPathSegment.setTarget(targetType); if (targetType instanceof AbstractRoleType) { - evaluateAbstractRole(assignment, assignmentPathSegment, (AbstractRoleType)targetType, source, sourceDescription, + evaluateAbstractRole(assignment, assignmentPathSegment, evaluateOld, (AbstractRoleType)targetType, source, sourceDescription, assignmentPath, task, result); if (targetType instanceof OrgType && assignmentPath.getEvaluationOrder() == 1) { PrismReferenceValue refVal = new PrismReferenceValue(); @@ -379,8 +371,8 @@ private void evaluateTarget(EvaluatedAssignment assignment, AssignmentPathSegmen } } - private void evaluateAbstractRole(EvaluatedAssignment assignment, AssignmentPathSegment assignmentPathSegment, - AbstractRoleType role, ObjectType source, String sourceDescription, + private void evaluateAbstractRole(EvaluatedAssignment assignment, AssignmentPathSegment assignmentPathSegment, + boolean evaluateOld, AbstractRoleType role, ObjectType source, String sourceDescription, AssignmentPath assignmentPath, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { assertSource(source, assignment); @@ -397,7 +389,10 @@ private void evaluateAbstractRole(EvaluatedAssignment assignment, AssignmentPath } } for (AssignmentType roleInducement : role.getInducement()) { - AssignmentPathSegment roleAssignmentPathSegment = new AssignmentPathSegment(roleInducement, null); + ItemDeltaItem> roleInducementIdi = new ItemDeltaItem<>(); + roleInducementIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(roleInducement)); + roleInducementIdi.recompute(); + AssignmentPathSegment roleAssignmentPathSegment = new AssignmentPathSegment(roleInducementIdi, null); roleAssignmentPathSegment.setSource(role); String subSourceDescription = role+" in "+sourceDescription; Integer inducementOrder = roleInducement.getOrder(); @@ -412,7 +407,7 @@ private void evaluateAbstractRole(EvaluatedAssignment assignment, AssignmentPath roleAssignmentPathSegment.setEvaluateConstructions(true); roleAssignmentPathSegment.setEvaluationOrder(evaluationOrder); roleAssignmentPathSegment.setOrderOneObject(orderOneObject); - evaluateAssignment(assignment, roleAssignmentPathSegment, role, subSourceDescription, assignmentPath, task, result); + evaluateAssignment(assignment, roleAssignmentPathSegment, evaluateOld, role, subSourceDescription, assignmentPath, task, result); // } else if (inducementOrder < assignmentPath.getEvaluationOrder()) { // LOGGER.trace("Follow({}) inducement({}) in role {}", // new Object[]{evaluationOrder, inducementOrder, source}); @@ -431,13 +426,16 @@ private void evaluateAbstractRole(EvaluatedAssignment assignment, AssignmentPath LOGGER.trace("E{}: follow assignment {} in {}", new Object[]{evaluationOrder, dumpAssignment(roleAssignment), role}); } - AssignmentPathSegment roleAssignmentPathSegment = new AssignmentPathSegment(roleAssignment, null); + ItemDeltaItem> roleAssignmentIdi = new ItemDeltaItem<>(); + roleAssignmentIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(roleAssignment)); + roleAssignmentIdi.recompute(); + AssignmentPathSegment roleAssignmentPathSegment = new AssignmentPathSegment(roleAssignmentIdi, null); roleAssignmentPathSegment.setSource(role); String subSourceDescription = role+" in "+sourceDescription; roleAssignmentPathSegment.setEvaluateConstructions(false); roleAssignmentPathSegment.setEvaluationOrder(evaluationOrder+1); roleAssignmentPathSegment.setOrderOneObject(orderOneObject); - evaluateAssignment(assignment, roleAssignmentPathSegment, role, subSourceDescription, assignmentPath, task, result); + evaluateAssignment(assignment, roleAssignmentPathSegment, evaluateOld, role, subSourceDescription, assignmentPath, task, result); } for(AuthorizationType authorizationType: role.getAuthorization()) { Authorization authorization = createAuthorization(authorizationType); @@ -462,15 +460,15 @@ private Authorization createAuthorization(AuthorizationType authorizationType) { return authorization; } - private void assertSource(ObjectType source, EvaluatedAssignment assignment) { + private void assertSource(ObjectType source, EvaluatedAssignment assignment) { if (source == null) { throw new IllegalArgumentException("Source cannot be null (while evaluating assignment "+assignment+")"); } } - private void assertSource(ObjectType source, AssignmentType assignmentType) { + private void assertSource(ObjectType source, ItemDeltaItem> assignmentIdi) { if (source == null) { - throw new IllegalArgumentException("Source cannot be null (while evaluating assignment "+assignmentType+")"); + throw new IllegalArgumentException("Source cannot be null (while evaluating assignment "+assignmentIdi.getAnyItem()+")"); } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPath.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPath.java index 3d93829fcd5..876b021572f 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPath.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPath.java @@ -18,6 +18,8 @@ import java.util.ArrayList; import java.util.List; +import com.evolveum.midpoint.model.common.expression.ItemDeltaItem; +import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType; @@ -36,9 +38,9 @@ public AssignmentPath() { segments = createNewSegments(); } - AssignmentPath(AssignmentType assignmentType) { + AssignmentPath(ItemDeltaItem> assignmentIdi) { this.segments = createNewSegments(); - segments.add(new AssignmentPathSegment(assignmentType, null)); + segments.add(new AssignmentPathSegment(assignmentIdi, null)); } private List createNewSegments() { @@ -58,8 +60,8 @@ public void remove(AssignmentPathSegment segment) { } - public AssignmentType getFirstAssignment() { - return segments.get(0).getAssignmentType(); + public AssignmentPathSegment getFirstAssignmentSegment() { + return segments.get(0); } public boolean isEmpty() { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegment.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegment.java index 6e925efa761..1e5d7529680 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegment.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathSegment.java @@ -15,6 +15,13 @@ */ package com.evolveum.midpoint.model.impl.lens; +import java.util.Collection; + +import com.evolveum.midpoint.model.common.expression.ItemDeltaItem; +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.PrismContainer; +import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; @@ -26,7 +33,7 @@ */ public class AssignmentPathSegment implements DebugDumpable { - private AssignmentType assignmentType; + private ItemDeltaItem> assignmentIdi; private ObjectType target; private ObjectType source; private boolean evaluateConstructions = true; @@ -34,18 +41,18 @@ public class AssignmentPathSegment implements DebugDumpable { private int evaluationOrder; private ObjectType varThisObject; - AssignmentPathSegment(AssignmentType assignmentType, ObjectType target) { + AssignmentPathSegment(ItemDeltaItem> assignmentIdi, ObjectType target) { super(); - this.assignmentType = assignmentType; + this.assignmentIdi = assignmentIdi; this.target = target; } - public AssignmentType getAssignmentType() { - return assignmentType; + public ItemDeltaItem> getAssignmentIdi() { + return assignmentIdi; } - public void setAssignmentType(AssignmentType assignmentType) { - this.assignmentType = assignmentType; + public void setAssignmentIdi(ItemDeltaItem> assignmentIdi) { + this.assignmentIdi = assignmentIdi; } public ObjectType getTarget() { @@ -100,7 +107,7 @@ public void setOrderOneObject(ObjectType varThisObject) { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((assignmentType == null) ? 0 : assignmentType.hashCode()); + result = prime * result + ((assignmentIdi == null) ? 0 : assignmentIdi.hashCode()); result = prime * result + ((source == null) ? 0 : source.hashCode()); result = prime * result + ((target == null) ? 0 : target.hashCode()); return result; @@ -115,10 +122,10 @@ public boolean equals(Object obj) { if (getClass() != obj.getClass()) return false; AssignmentPathSegment other = (AssignmentPathSegment) obj; - if (assignmentType == null) { - if (other.assignmentType != null) + if (assignmentIdi == null) { + if (other.assignmentIdi != null) return false; - } else if (!assignmentType.equals(other.assignmentType)) + } else if (!assignmentIdi.equals(other.assignmentIdi)) return false; if (source == null) { if (other.source != null) @@ -142,8 +149,12 @@ public String toString() { }; sb.append(" "); sb.append(source).append(" "); - if (assignmentType.getConstruction() != null) { - sb.append("Constr '"+assignmentType.getConstruction().getDescription()+"' "); + PrismContainer assignment = (PrismContainer) assignmentIdi.getAnyItem(); + if (assignment != null) { + AssignmentType assignmentType = assignment.getValue().asContainerable(); + if (assignmentType.getConstruction() != null) { + sb.append("Constr '"+assignmentType.getConstruction().getDescription()+"' "); + } } if (target != null) { sb.append("-> ").append(target); @@ -168,7 +179,7 @@ public String debugDump(int indent) { sb.append("\n"); DebugUtil.debugDumpWithLabel(sb, "evaluationOrder", evaluationOrder, indent + 1); sb.append("\n"); - DebugUtil.debugDumpWithLabel(sb, "assignmentType", assignmentType.toString(), indent + 1); + DebugUtil.debugDumpWithLabel(sb, "assignment", assignmentIdi.toString(), indent + 1); sb.append("\n"); DebugUtil.debugDumpWithLabel(sb, "target", target==null?"null":target.toString(), indent + 1); sb.append("\n"); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathVariables.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathVariables.java index 16b1837c4e0..16ba33e1d4d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathVariables.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPathVariables.java @@ -15,6 +15,7 @@ */ package com.evolveum.midpoint.model.impl.lens; +import com.evolveum.midpoint.model.common.expression.ItemDeltaItem; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType; @@ -26,50 +27,50 @@ */ public class AssignmentPathVariables { - private PrismContainerValue magicAssignment; - private PrismContainerValue immediateAssignment; - private PrismContainerValue thisAssignment; - private PrismContainerValue focusAssignment; + private ItemDeltaItem> magicAssignment; + private ItemDeltaItem> immediateAssignment; + private ItemDeltaItem> thisAssignment; + private ItemDeltaItem> focusAssignment; private PrismObject immediateRole; - - public PrismContainerValue getMagicAssignment() { + + public ItemDeltaItem> getMagicAssignment() { return magicAssignment; } - - public void setMagicAssignment(PrismContainerValue magicAssignment) { + + public void setMagicAssignment(ItemDeltaItem> magicAssignment) { this.magicAssignment = magicAssignment; } - - public PrismContainerValue getImmediateAssignment() { + + public ItemDeltaItem> getImmediateAssignment() { return immediateAssignment; } - - public void setImmediateAssignment(PrismContainerValue immediateAssignment) { + + public void setImmediateAssignment(ItemDeltaItem> immediateAssignment) { this.immediateAssignment = immediateAssignment; } - - public PrismContainerValue getThisAssignment() { + + public ItemDeltaItem> getThisAssignment() { return thisAssignment; } - - public void setThisAssignment(PrismContainerValue thisAssignment) { + + public void setThisAssignment(ItemDeltaItem> thisAssignment) { this.thisAssignment = thisAssignment; } - - public PrismContainerValue getFocusAssignment() { + + public ItemDeltaItem> getFocusAssignment() { return focusAssignment; } - public void setFocusAssignment(PrismContainerValue focusAssignment) { + public void setFocusAssignment(ItemDeltaItem> focusAssignment) { this.focusAssignment = focusAssignment; } public PrismObject getImmediateRole() { return immediateRole; } - + public void setImmediateRole(PrismObject immediateRole) { this.immediateRole = immediateRole; } - + } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java index 4045da79b76..d8e6540b303 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java @@ -90,7 +90,7 @@ public class Construction implements DebugDumpable, Seriali private OriginType originType; private String channel; private LensContext lensContext; - private ObjectDeltaObject userOdo; + private ObjectDeltaObject focusOdo; private ResourceType resource; private ObjectResolver objectResolver; private MappingFactory mappingFactory; @@ -142,8 +142,8 @@ public void setLensContext(LensContext lensContext) { this.lensContext = lensContext; } - public void setUserOdo(ObjectDeltaObject userOdo) { - this.userOdo = userOdo; + public void setFocusOdo(ObjectDeltaObject focusOdo) { + this.focusOdo = focusOdo; } public ObjectResolver getObjectResolver() { @@ -178,6 +178,10 @@ public void setMappingFactory(MappingFactory mappingFactory) { this.mappingFactory = mappingFactory; } + public RefinedObjectClassDefinition getRefinedObjectClassDefinition() { + return refinedObjectClassDefinition; + } + public ShadowKindType getKind() { if (refinedObjectClassDefinition == null) { throw new IllegalStateException("Kind can only be fetched from evaluated Construction"); @@ -435,12 +439,12 @@ private Mapping evaluateMapping(Mapping mapping, QN return null; } - mapping.addVariableDefinition(ExpressionConstants.VAR_USER, userOdo); - mapping.addVariableDefinition(ExpressionConstants.VAR_FOCUS, userOdo); + mapping.addVariableDefinition(ExpressionConstants.VAR_USER, focusOdo); + mapping.addVariableDefinition(ExpressionConstants.VAR_FOCUS, focusOdo); mapping.addVariableDefinition(ExpressionConstants.VAR_SOURCE, source); mapping.setMappingQName(mappingQName); - mapping.setSourceContext(userOdo); - mapping.setRootNode(userOdo); + mapping.setSourceContext(focusOdo); + mapping.setRootNode(focusOdo); mapping.setDefaultTargetDefinition(outputDefinition); mapping.setOriginType(originType); mapping.setOriginObject(source); @@ -456,10 +460,10 @@ private Mapping evaluateMapping(Mapping mapping, QN // Set condition masks. There are used as a brakes to avoid evaluating to nonsense values in case user is not present // (e.g. in old values in ADD situations and new values in DELETE situations). - if (userOdo.getOldObject() == null) { + if (focusOdo.getOldObject() == null) { mapping.setConditionMaskOld(false); } - if (userOdo.getNewObject() == null) { + if (focusOdo.getNewObject() == null) { mapping.setConditionMaskNew(false); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java index 48fdb5f3eec..8cf2b64bea6 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java @@ -18,8 +18,10 @@ import java.util.ArrayList; import java.util.Collection; +import com.evolveum.midpoint.model.common.expression.ItemDeltaItem; import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject; import com.evolveum.midpoint.model.common.mapping.Mapping; +import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.PrismReferenceValue; @@ -48,7 +50,7 @@ public class EvaluatedAssignment implements DebugDumpable { private static final Trace LOGGER = TraceManager.getTrace(EvaluatedAssignment.class); - private AssignmentType assignmentType; + private ItemDeltaItem> assignmentIdi; private Collection> constructions; private Collection orgRefVals; private Collection authorizations; @@ -63,13 +65,17 @@ public EvaluatedAssignment() { authorizations = new ArrayList<>(); focusMappings = new ArrayList<>(); } - - public AssignmentType getAssignmentType() { - return assignmentType; + + public ItemDeltaItem> getAssignmentIdi() { + return assignmentIdi; } - public void setAssignmentType(AssignmentType assignmentType) { - this.assignmentType = assignmentType; + public void setAssignmentIdi(ItemDeltaItem> assignmentIdi) { + this.assignmentIdi = assignmentIdi; + } + + public AssignmentType getAssignmentType() { + return assignmentIdi.getItemNew().getValue(0).asContainerable(); } public Collection> getConstructions() { @@ -138,7 +144,7 @@ public Collection getResources(OperationResult result) throws Obje public void evaluateConstructions(ObjectDeltaObject focusOdo, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException { for (Construction construction :constructions) { - construction.setUserOdo(focusOdo); + construction.setFocusOdo(focusOdo); LOGGER.trace("Evaluating construction '{}' in {}", construction, construction.getSource()); construction.evaluate(task, result); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java index 46b760352bb..77a1bb06e6d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensUtil.java @@ -457,7 +457,7 @@ private static boolean hasValue(Item item, ItemDelta clonedItem = item.clone(); - itemDelta.applyTo(clonedItem); + itemDelta.applyToMatchingPath(clonedItem); return !clonedItem.isEmpty(); } } @@ -1040,41 +1040,34 @@ public static AssignmentPathVariables computeAssignmentPathVariables(AssignmentP return null; } AssignmentPathVariables vars = new AssignmentPathVariables(); + Iterator iterator = assignmentPath.getSegments().iterator(); while (iterator.hasNext()) { AssignmentPathSegment segment = iterator.next(); - AssignmentType segmentAssignmentType = segment.getAssignmentType(); - PrismContainerValue segmentAssignmentCVal = segmentAssignmentType.asPrismContainerValue(); - PrismContainerDefinition assignmentDef = segmentAssignmentCVal.getParent().getDefinition(); - + ItemDeltaItem> segmentAssignmentIdi = segment.getAssignmentIdi(); + + ItemDeltaItem> magicAssignmentIdi; // Magic assignment if (vars.getMagicAssignment() == null) { - PrismContainerValue magicAssignment = segmentAssignmentCVal.clone(); - // Make sure that the magic assignment has a valid parent so it can be serialized - PrismContainer assignmentCont = assignmentDef.instantiate(); - assignmentCont.add(magicAssignment); - vars.setMagicAssignment(magicAssignment); + magicAssignmentIdi = segmentAssignmentIdi.clone(); + vars.setMagicAssignment(magicAssignmentIdi); } else { // Collect extension values from the assignment extension - PrismContainer magicExtension = vars.getMagicAssignment().findOrCreateContainer(AssignmentType.F_EXTENSION); - mergeExtension(magicExtension, segmentAssignmentCVal.findContainer(AssignmentType.F_EXTENSION)); + magicAssignmentIdi = vars.getMagicAssignment(); + mergeExtension(magicAssignmentIdi, segmentAssignmentIdi); } // Collect extension values from the source object extension - PrismContainer magicExtension = vars.getMagicAssignment().findOrCreateContainer(AssignmentType.F_EXTENSION); ObjectType segmentSource = segment.getSource(); if (segmentSource != null) { - mergeExtension(magicExtension, segmentSource.asPrismObject().findContainer(AssignmentType.F_EXTENSION)); + mergeExtension(magicAssignmentIdi, segmentSource.asPrismObject()); } // immediate assignment (use assignment from previous iteration) vars.setImmediateAssignment(vars.getThisAssignment()); // this assignment - PrismContainerValue thisAssignment = segmentAssignmentCVal.clone(); - // Make sure that the assignment has a valid parent so it can be serialized - PrismContainer assignmentCont = assignmentDef.instantiate(); - assignmentCont.add(thisAssignment); + ItemDeltaItem> thisAssignment = segmentAssignmentIdi.clone(); vars.setThisAssignment(thisAssignment); if (iterator.hasNext() && segmentSource instanceof AbstractRoleType) { @@ -1082,13 +1075,59 @@ public static AssignmentPathVariables computeAssignmentPathVariables(AssignmentP } } - AssignmentType focusAssignment = assignmentPath.getFirstAssignment(); - vars.setFocusAssignment(focusAssignment.asPrismContainerValue()); + AssignmentPathSegment focusAssignmentSegment = assignmentPath.getFirstAssignmentSegment(); + ItemDeltaItem> focusAssignment = focusAssignmentSegment.getAssignmentIdi().clone(); + vars.setFocusAssignment(focusAssignment); return vars; } - private static void mergeExtension(PrismContainer magicExtension, PrismContainer segmentExtension) throws SchemaException { + private static void mergeExtension(ItemDeltaItem> destIdi, ItemDeltaItem> srcIdi) throws SchemaException { + mergeExtension(destIdi.getItemOld(), srcIdi.getItemOld()); + mergeExtension(destIdi.getItemNew(), srcIdi.getItemNew()); + if (srcIdi.getDelta() != null || srcIdi.getSubItemDeltas() != null) { + throw new UnsupportedOperationException("Merge of IDI with deltas not supported"); + } + } + + private static void mergeExtension(Item> dstItem, + Item> srcItem) throws SchemaException { + if (srcItem == null || dstItem == null) { + return; + } + PrismContainer srcExtension = ((PrismContainer)srcItem).findContainer(AssignmentType.F_EXTENSION); + mergeExtensionContainers(dstItem, srcExtension); + } + + private static void mergeExtension(ItemDeltaItem> destIdi, + PrismObject srcObject) throws SchemaException { + if (srcObject == null) { + return; + } + + PrismContainer srcExtension = srcObject.findContainer(ObjectType.F_EXTENSION); + + mergeExtensionContainers(destIdi.getItemNew(), srcExtension); + mergeExtensionContainers(destIdi.getItemOld(), srcExtension); + } + + private static void mergeExtensionContainers(Item> dstItem, PrismContainer srcExtension) throws SchemaException { + if (dstItem == null) { + return; + } + PrismContainer dstContainer = (PrismContainer) dstItem; + if (srcExtension != null && !srcExtension.getValue().isEmpty()) { + PrismContainer dstExtension = dstContainer.findOrCreateContainer(AssignmentType.F_EXTENSION); + for (Item srcExtensionItem: srcExtension.getValue().getItems()) { + Item magicItem = dstExtension.findItem(srcExtensionItem.getElementName()); + if (magicItem == null) { + dstExtension.add(srcExtensionItem.clone()); + } + } + } + } + + private static void mergeExtension(PrismContainer magicExtension, PrismContainer segmentExtension) throws SchemaException { if (segmentExtension != null && !segmentExtension.getValue().isEmpty()) { for (Item segmentItem: segmentExtension.getValue().getItems()) { Item magicItem = magicExtension.findItem(segmentItem.getElementName()); @@ -1188,4 +1227,22 @@ private static void checkObjectPolicy(LensFocusContext } } } + + public static PrismContainer createAssignmentSingleValueContainerClone(AssignmentType assignmentType) throws SchemaException { + PrismContainerValue assignmentCVal = assignmentType.asPrismContainerValue(); + PrismContainerDefinition def = assignmentCVal.getParent().getDefinition().clone(); + // Make it appear to be single-value. Therefore paths without segment IDs will work. + def.setMaxOccurs(1); + PrismContainer assignmentCont = def.instantiate(); + assignmentCont.add(assignmentCVal.clone()); + return assignmentCont; + } + + public static AssignmentType getAssignmentType(ItemDeltaItem> assignmentIdi, boolean old) { + if (old) { + return ((PrismContainer)assignmentIdi.getItemOld()).getValue(0).asContainerable(); + } else { + return ((PrismContainer)assignmentIdi.getItemNew()).getValue(0).asContainerable(); + } + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ActivationProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ActivationProcessor.java index 90a435647cd..8e2aae76370 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ActivationProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ActivationProcessor.java @@ -310,7 +310,7 @@ public void processActivationMetadata(LensContext conte if (statusDelta != null && !statusDelta.isDelete()) { // timestamps - PrismProperty statusPropNew = (PrismProperty) statusDelta.getItemNew(); + PrismProperty statusPropNew = (PrismProperty) statusDelta.getItemNewMatchingPath(null); ActivationStatusType statusNew = statusPropNew.getRealValue(); PropertyDelta timestampDelta = LensUtil.createActivationTimestampDelta(statusNew, now, getActivationDefinition(), OriginType.OUTBOUND); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java index 147955fb237..ce27e55b016 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java @@ -23,6 +23,7 @@ import com.evolveum.midpoint.model.api.ModelExecuteOptions; import com.evolveum.midpoint.model.api.PolicyViolationException; import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; +import com.evolveum.midpoint.model.common.expression.ItemDeltaItem; import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject; import com.evolveum.midpoint.model.common.mapping.Mapping; import com.evolveum.midpoint.model.common.mapping.MappingFactory; @@ -188,7 +189,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo ContainerDelta assignmentDelta = getExecutionWaveAssignmentDelta(focusContext); assignmentDelta.expand(focusContext.getObjectCurrent()); - LOGGER.trace("Assignment delta {}", assignmentDelta.debugDump()); + LOGGER.trace("Assignment delta:\n{}", assignmentDelta.debugDump()); Collection> changedAssignments = assignmentDelta.getValues(AssignmentType.class); @@ -236,32 +237,36 @@ private void processAssignmentsProjectionsWithFocus(LensCo for (PrismContainerValue assignmentCVal : allAssignments) { AssignmentType assignmentType = assignmentCVal.asContainerable(); PrismContainerValue assignmentCValOld = assignmentCVal; + ItemDeltaItem> assignmentIdi = new ItemDeltaItem<>(); + assignmentIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(assignmentType)); boolean forceRecon = false; // This really means whether the WHOLE assignment was changed (e.g. added/delted/replaced). It tells nothing // about "micro-changes" inside assignment, these will be processed later. - boolean isAssignmentChanged = containsRealValue(changedAssignments,assignmentCVal); + boolean isAssignmentChanged = containsRealValue(changedAssignments, assignmentCVal); String assignmentPlacementDesc; + if (isAssignmentChanged) { + // Whole assignment added or deleted assignmentPlacementDesc = "delta for "+source; } else { assignmentPlacementDesc = source.toString(); Collection> assignmentItemDeltas = getExecutionWaveAssignmentItemDeltas(focusContext, assignmentCVal.getId()); if (assignmentItemDeltas != null && !assignmentItemDeltas.isEmpty()) { - // Make sure we clone first to avoid side-effects - PrismContainerValue assignmentCValClone = assignmentCVal.clone(); - assignmentCValClone.setParent(assignmentCVal.getParent()); - assignmentCVal = assignmentCValClone; - assignmentType = assignmentCVal.asContainerable(); - applyAssignemntMicroDeltas(assignmentItemDeltas, assignmentCVal); - // We do not exactly know what was changed. This may be a replace change, etc. - // Even if we know we do not bother to compute it now. This is not a performance-critical case anyway - // So we just force reconciliation for this case. It will sort it out. + // Small changes inside assignment, but otherwise the assignment stays as it is (not added or deleted) + assignmentIdi.setSubItemDeltas(assignmentItemDeltas); + + // The subItemDeltas above will handle some changes. But not other. + // E.g. a replace of the whole construction will not be handled properly. + // Therefore we force recon to sort it out. forceRecon = true; + isAssignmentChanged = true; } } + assignmentIdi.recompute(); + // The following code is using collectToAccountMap() to collect the account constructions to one of the three "delta" // sets (zero, plus, minus). It is handling several situations that needs to be handled specially. // It is also collecting assignments to evaluatedAssignmentTriple. @@ -274,7 +279,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo if (LOGGER.isTraceEnabled()) { LOGGER.trace("Processing focus delete for: {}", SchemaDebugUtil.prettyPrint(assignmentCVal)); } - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentType, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, false, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } @@ -296,21 +301,21 @@ private void processAssignmentsProjectionsWithFocus(LensCo boolean willHaveValue = assignmentDelta.isValueToReplace(assignmentCVal, true); if (hadValue && willHaveValue) { // No change - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentType, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, false, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } collectToZero(evaluatedAssignmentTriple, evaluatedAssignment, forceRecon); } else if (willHaveValue) { // add - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentType, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, false, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } collectToPlus(evaluatedAssignmentTriple, evaluatedAssignment, forceRecon); } else if (hadValue) { // delete - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentCValOld.asContainerable(), context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, true, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } @@ -336,7 +341,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo if (LOGGER.isTraceEnabled()) { LOGGER.trace("Processing changed assignment, phantom add: {}", SchemaDebugUtil.prettyPrint(assignmentCVal)); } - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentType, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, false, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } @@ -345,7 +350,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo if (LOGGER.isTraceEnabled()) { LOGGER.trace("Processing changed assignment, add: {}", SchemaDebugUtil.prettyPrint(assignmentCVal)); } - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentType, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, false, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } @@ -357,7 +362,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo if (LOGGER.isTraceEnabled()) { LOGGER.trace("Processing changed assignment, delete: {}", SchemaDebugUtil.prettyPrint(assignmentCVal)); } - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentCValOld.asContainerable(), context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, true, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } @@ -376,7 +381,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo if (LOGGER.isTraceEnabled()) { LOGGER.trace("Processing changed assignment, minor change (add={}, delete={}, valid={}): {}", new Object[]{isAdd, isDelete, isValid, SchemaDebugUtil.prettyPrint(assignmentCVal)}); } - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentType, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, false, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } @@ -386,7 +391,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo if (LOGGER.isTraceEnabled()) { LOGGER.trace("Processing changed assignment, assignment becomes valid (add={}, delete={}): {}", new Object[]{isAdd, isDelete, SchemaDebugUtil.prettyPrint(assignmentCVal)}); } - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentType, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, false, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } @@ -396,7 +401,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo if (LOGGER.isTraceEnabled()) { LOGGER.trace("Processing changed assignment, assignment becomes invalid (add={}, delete={}): {}", new Object[]{isAdd, isDelete, SchemaDebugUtil.prettyPrint(assignmentCVal)}); } - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentCValOld.asContainerable(), context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, false, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } @@ -410,7 +415,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo LOGGER.trace("Processing unchanged assignment {}", new Object[]{SchemaDebugUtil.prettyPrint(assignmentCVal)}); } boolean isValid = LensUtil.isValid(assignmentType, now, activationComputer); - EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentType, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = evaluateAssignment(assignmentIdi, false, context, source, assignmentEvaluator, assignmentPlacementDesc, task, result); if (evaluatedAssignment == null) { continue; } @@ -756,18 +761,18 @@ private Collection> mergeAssignments( return all; } - private EvaluatedAssignment evaluateAssignment(AssignmentType assignmentType, - LensContext context, ObjectType source, AssignmentEvaluator assignmentEvaluator, + private EvaluatedAssignment evaluateAssignment(ItemDeltaItem> assignmentIdi, + boolean evaluateOld, LensContext context, ObjectType source, AssignmentEvaluator assignmentEvaluator, String assignmentPlacementDesc, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, PolicyViolationException { try{ // Evaluate assignment. This follows to the assignment targets, follows to the inducements, // evaluates all the expressions, etc. - EvaluatedAssignment evaluatedAssignment = assignmentEvaluator.evaluate(assignmentType, source, assignmentPlacementDesc, task, result); + EvaluatedAssignment evaluatedAssignment = assignmentEvaluator.evaluate(assignmentIdi, evaluateOld, source, assignmentPlacementDesc, task, result); context.rememberResources(evaluatedAssignment.getResources(result)); return evaluatedAssignment; } catch (ObjectNotFoundException ex){ if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Processing of assignment resulted in error {}: {}", ex, SchemaDebugUtil.prettyPrint(assignmentType)); + LOGGER.trace("Processing of assignment resulted in error {}: {}", ex, SchemaDebugUtil.prettyPrint(LensUtil.getAssignmentType(assignmentIdi, evaluateOld))); } if (ModelExecuteOptions.isForce(context.getOptions())){ return null; @@ -775,6 +780,7 @@ private EvaluatedAssignment evaluateAssignment(Assignme ModelUtils.recordFatalError(result, ex); return null; } catch (SchemaException ex){ + AssignmentType assignmentType = LensUtil.getAssignmentType(assignmentIdi, evaluateOld); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Processing of assignment resulted in error {}: {}", ex, SchemaDebugUtil.prettyPrint(assignmentType)); } @@ -863,20 +869,6 @@ private boolean isForceRecon(ConstructionPack accountConstructionPack) { return accountConstructionPack.isForceRecon(); } - - private void applyAssignemntMicroDeltas(Collection> assignmentItemDeltas, PrismContainerValue assignmentCVal) throws SchemaException { - for (ItemDelta assignmentItemDelta: assignmentItemDeltas) { - ItemDelta assignmentItemDeltaClone = assignmentItemDelta.clone(); - ItemPath deltaPath = assignmentItemDeltaClone.getParentPath(); - ItemPath tailPath = deltaPath.tail(); - if (tailPath.first() instanceof IdItemPathSegment) { - tailPath = tailPath.tail(); - } - assignmentItemDeltaClone.setParentPath(tailPath); - assignmentItemDeltaClone.applyTo(assignmentCVal); - } - } - /** * Set 'legal' flag for the accounts that does not have it already */ diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java index 125b7e6c03c..c01ff90d47e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java @@ -123,18 +123,18 @@ void processPasswordPolicy(LensFocusContext focusContex passwordValueDelta = userDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE); if (passwordValueDelta == null) { LOGGER.trace("Skipping processing password policies. User delta does not contain password change."); - return ; + return; } if (userDelta.getChangeType() == ChangeType.MODIFY && passwordValueDelta != null) { if (passwordValueDelta.isAdd()) { - password = passwordValueDelta.getPropertyNew(); + password = (PrismProperty) passwordValueDelta.getItemNewMatchingPath(null); } else if (passwordValueDelta.isDelete()) { password = null; } else { - password = passwordValueDelta.getPropertyNew(); + password = (PrismProperty) passwordValueDelta.getItemNewMatchingPath(null); } } else { - password = passwordValueDelta.getPropertyNew(); + password = (PrismProperty) passwordValueDelta.getItemNewMatchingPath(null); } } } @@ -302,7 +302,7 @@ void processPasswordPolicy(LensProjectionContext projecti LOGGER.trace("Skipping processing password policies. Shadow delta does not contain password change."); return; } - password = passwordValueDelta.getPropertyNew(); + password = (PrismProperty) passwordValueDelta.getItemNewMatchingPath(null); } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/UserProfileServiceImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/UserProfileServiceImpl.java index 8657fb230df..0f740b36458 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/UserProfileServiceImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/UserProfileServiceImpl.java @@ -19,11 +19,14 @@ import com.evolveum.midpoint.common.ActivationComputer; import com.evolveum.midpoint.common.Clock; import com.evolveum.midpoint.model.api.PolicyViolationException; +import com.evolveum.midpoint.model.common.expression.ItemDeltaItem; import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject; import com.evolveum.midpoint.model.common.mapping.MappingFactory; import com.evolveum.midpoint.model.impl.UserComputer; import com.evolveum.midpoint.model.impl.lens.AssignmentEvaluator; import com.evolveum.midpoint.model.impl.lens.EvaluatedAssignment; +import com.evolveum.midpoint.model.impl.lens.LensUtil; +import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ObjectDelta; @@ -157,7 +160,7 @@ private void addAuthorizations(MidPointPrincipal principal) { return; } - AssignmentEvaluator assignmentEvaluator = new AssignmentEvaluator(); + AssignmentEvaluator assignmentEvaluator = new AssignmentEvaluator<>(); assignmentEvaluator.setRepository(repositoryService); assignmentEvaluator.setFocusOdo(new ObjectDeltaObject(userType.asPrismObject(), null, userType.asPrismObject())); assignmentEvaluator.setChannel(null); @@ -174,7 +177,10 @@ private void addAuthorizations(MidPointPrincipal principal) { OperationResult result = new OperationResult(UserProfileServiceImpl.class.getName() + ".addAuthorizations"); for(AssignmentType assignmentType: userType.getAssignment()) { try { - EvaluatedAssignment assignment = assignmentEvaluator.evaluate(assignmentType, userType, userType.toString(), null, result); + ItemDeltaItem> assignmentIdi = new ItemDeltaItem<>(); + assignmentIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(assignmentType)); + assignmentIdi.recompute(); + EvaluatedAssignment assignment = assignmentEvaluator.evaluate(assignmentIdi, false, userType, userType.toString(), null, result); if (assignment.isValid()) { authorizations.addAll(assignment.getAuthorizations()); } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/AbstractLensTest.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/AbstractLensTest.java index 1b339551f98..c6fa54ad195 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/AbstractLensTest.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/AbstractLensTest.java @@ -54,6 +54,7 @@ public abstract class AbstractLensTest extends AbstractInternalModelIntegrationT protected static final File TEST_DIR_COMMON = new File("./src/test/resources/common"); protected static final File ASSIGNMENT_DIRECT_FILE = new File(TEST_DIR, "assignment-direct.xml"); + protected static final File ASSIGNMENT_DIRECT_EXPRESSION_FILE = new File(TEST_DIR, "assignment-direct-expression.xml"); protected static final File USER_DRAKE_FILE = new File(TEST_DIR, "user-drake.xml"); @@ -78,6 +79,9 @@ public abstract class AbstractLensTest extends AbstractInternalModelIntegrationT protected static final File ROLE_PIRATE_FILE = new File(TEST_DIR, "role-pirate.xml"); protected static final String ROLE_PIRATE_OID = "12345678-d34d-b33f-f00d-555555556666"; + protected static final File ROLE_MUTINIER_FILE = new File(TEST_DIR, "role-mutinier.xml"); + protected static final String ROLE_MUTINIER_OID = "12345678-d34d-b33f-f00d-555555556668"; + protected static final File ORG_BRETHREN_FILE = new File(TEST_DIR, "org-brethren.xml"); protected static final String ORG_BRETHREN_OID = "9c6bfc9a-ca01-11e3-a5aa-001e8c717e5b"; protected static final String ORG_BRETHREN_INDUCED_ORGANIZATION = "Pirate Brethren"; diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentEvaluator.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentEvaluator.java index 562175153b3..86b158f54bd 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentEvaluator.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2014 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ import static org.testng.AssertJUnit.assertNotNull; import static com.evolveum.midpoint.test.IntegrationTestTools.*; +import java.util.Collection; + import javax.xml.bind.JAXBException; import org.springframework.beans.factory.annotation.Autowired; @@ -29,14 +31,25 @@ import com.evolveum.midpoint.common.ActivationComputer; import com.evolveum.midpoint.common.Clock; +import com.evolveum.midpoint.model.common.expression.ItemDeltaItem; import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject; +import com.evolveum.midpoint.model.common.mapping.Mapping; +import com.evolveum.midpoint.model.common.mapping.MappingFactory; import com.evolveum.midpoint.model.impl.AbstractInternalModelIntegrationTest; import com.evolveum.midpoint.model.impl.lens.AssignmentEvaluator; import com.evolveum.midpoint.model.impl.lens.EvaluatedAssignment; import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismPropertyValue; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.path.IdItemPathSegment; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.path.NameItemPathSegment; import com.evolveum.midpoint.prism.util.PrismAsserts; +import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ObjectResolver; @@ -66,11 +79,10 @@ public class TestAssignmentEvaluator extends AbstractLensTest { @Autowired(required=true) private ActivationComputer activationComputer; - - public TestAssignmentEvaluator() throws JAXBException { - super(); - } + @Autowired(required=true) + private MappingFactory mappingFactory; + @Test public void testDirect() throws Exception { final String TEST_NAME = "testDirect"; @@ -79,38 +91,222 @@ public void testDirect() throws Exception { // GIVEN Task task = taskManager.createTaskInstance(TestAssignmentEvaluator.class.getName() + "." + TEST_NAME); OperationResult result = task.getResult(); - AssignmentEvaluator assignmentEvaluator = createAssignmentEvaluator(); + AssignmentEvaluator assignmentEvaluator = createAssignmentEvaluator(); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); AssignmentType assignmentType = unmarshallValueFromFile(ASSIGNMENT_DIRECT_FILE, AssignmentType.class); // We need to make sure that the assignment has a parent - PrismContainerDefinition assignmentContainerDefinition = userTypeJack.asPrismObject().getDefinition().findContainerDefinition(UserType.F_ASSIGNMENT); - PrismContainer assignmentContainer = assignmentContainerDefinition.instantiate(); + PrismContainerDefinition assignmentContainerDefinition = userTypeJack.asPrismObject().getDefinition().findContainerDefinition(UserType.F_ASSIGNMENT); + PrismContainer assignmentContainer = assignmentContainerDefinition.instantiate(); assignmentContainer.add(assignmentType.asPrismContainerValue().clone()); + ObjectDeltaObject userOdo = new ObjectDeltaObject<>(userTypeJack.asPrismObject(), null, null); + userOdo.recompute(); + + ItemDeltaItem> assignmentIdi = new ItemDeltaItem<>(); + assignmentIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(assignmentType)); + assignmentIdi.recompute(); + // WHEN - EvaluatedAssignment evaluatedAssignment = assignmentEvaluator.evaluate(assignmentType, userTypeJack, "testDirect", task, result); + TestUtil.displayWhen(TEST_NAME); + EvaluatedAssignment evaluatedAssignment = assignmentEvaluator.evaluate(assignmentIdi, false, userTypeJack, "testDirect", task, result); + evaluatedAssignment.evaluateConstructions(userOdo, task, result); // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + assertNotNull(evaluatedAssignment); display("Evaluated assignment",evaluatedAssignment.debugDump()); assertEquals(1,evaluatedAssignment.getConstructions().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); + + Construction construction = evaluatedAssignment.getConstructions().iterator().next(); + display("Evaluated construction", construction); + assertNotNull("No object class definition in construction", construction.getRefinedObjectClassDefinition()); } - private AssignmentEvaluator createAssignmentEvaluator() throws ObjectNotFoundException, SchemaException { - AssignmentEvaluator assignmentEvaluator = new AssignmentEvaluator(); - assignmentEvaluator.setRepository(repositoryService); + @Test + public void testDirectExpression() throws Exception { + final String TEST_NAME = "testDirectExpression"; + TestUtil.displayTestTile(this, TEST_NAME); - PrismObject userJack = userTypeJack.asPrismObject(); - assignmentEvaluator.setFocusOdo(new ObjectDeltaObject(userJack, null, null)); + // GIVEN + Task task = taskManager.createTaskInstance(TestAssignmentEvaluator.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); + + AssignmentType assignmentType = unmarshallValueFromFile(ASSIGNMENT_DIRECT_EXPRESSION_FILE, AssignmentType.class); + + // We need to make sure that the assignment has a parent + PrismContainerDefinition assignmentContainerDefinition = userTypeJack.asPrismObject().getDefinition().findContainerDefinition(UserType.F_ASSIGNMENT); + PrismContainer assignmentContainer = assignmentContainerDefinition.instantiate(); + assignmentContainer.add(assignmentType.asPrismContainerValue().clone()); + + ObjectDeltaObject userOdo = new ObjectDeltaObject<>(userTypeJack.asPrismObject(), null, null); + userOdo.recompute(); + AssignmentEvaluator assignmentEvaluator = createAssignmentEvaluator(userOdo); + + ItemDeltaItem> assignmentIdi = new ItemDeltaItem<>(); + assignmentIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(assignmentType)); + assignmentIdi.recompute(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + EvaluatedAssignment evaluatedAssignment = assignmentEvaluator.evaluate(assignmentIdi, false, userTypeJack, "testDirect", task, result); + evaluatedAssignment.evaluateConstructions(userOdo, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertNotNull(evaluatedAssignment); + display("Evaluated assignment",evaluatedAssignment); + assertEquals(1,evaluatedAssignment.getConstructions().size()); + PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); + + Construction construction = evaluatedAssignment.getConstructions().iterator().next(); + assertNotNull("No object class definition in construction", construction.getRefinedObjectClassDefinition()); + } + + @Test + public void testDirectExpressionReplaceDescription() throws Exception { + final String TEST_NAME = "testDirectExpressionReplaceDescription"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestAssignmentEvaluator.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + PrismObject user = userTypeJack.asPrismObject().clone(); + AssignmentType assignmentType = unmarshallValueFromFile(ASSIGNMENT_DIRECT_EXPRESSION_FILE, AssignmentType.class); + user.asObjectable().getAssignment().add(assignmentType.clone()); + + // We need to make sure that the assignment has a parent + PrismContainerDefinition assignmentContainerDefinition = user.getDefinition().findContainerDefinition(UserType.F_ASSIGNMENT); + PrismContainer assignmentContainer = assignmentContainerDefinition.instantiate(); + assignmentContainer.add(assignmentType.asPrismContainerValue().clone()); + + ItemPath path = new ItemPath( + new NameItemPathSegment(UserType.F_ASSIGNMENT), + new IdItemPathSegment(123L), + new NameItemPathSegment(AssignmentType.F_DESCRIPTION)); + ObjectDelta userDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, USER_JACK_OID, + path, prismContext, "captain"); + ObjectDeltaObject userOdo = new ObjectDeltaObject<>(user, userDelta, null); + userOdo.recompute(); + AssignmentEvaluator assignmentEvaluator = createAssignmentEvaluator(userOdo); + + ItemDeltaItem> assignmentIdi = new ItemDeltaItem<>(); + assignmentIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(assignmentType)); + assignmentIdi.setSubItemDeltas((Collection)userDelta.getModifications()); + assignmentIdi.recompute(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + EvaluatedAssignment evaluatedAssignment = assignmentEvaluator.evaluate(assignmentIdi, false, userTypeJack, "testDirect", task, result); + evaluatedAssignment.evaluateConstructions(userOdo, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertNotNull(evaluatedAssignment); + display("Evaluated assignment",evaluatedAssignment); + assertEquals(1,evaluatedAssignment.getConstructions().size()); + PrismAsserts.assertParentConsistency(user); + + Construction construction = evaluatedAssignment.getConstructions().iterator().next(); + assertNotNull("No object class definition in construction", construction.getRefinedObjectClassDefinition()); + assertEquals(1,construction.getAttributeMappings().size()); + Mapping> attributeMapping = (Mapping>) construction.getAttributeMappings().iterator().next(); + PrismValueDeltaSetTriple> outputTriple = attributeMapping.getOutputTriple(); + PrismAsserts.assertTripleNoZero(outputTriple); + PrismAsserts.assertTriplePlus(outputTriple, "The best captain the world has ever seen"); + PrismAsserts.assertTripleMinus(outputTriple, "The best pirate the world has ever seen"); + + } + + @Test + public void testDirectExpressionReplaceDescriptionFromNull() throws Exception { + final String TEST_NAME = "testDirectExpressionReplaceDescriptionFromNull"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestAssignmentEvaluator.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + PrismObject user = userTypeJack.asPrismObject().clone(); + AssignmentType assignmentType = unmarshallValueFromFile(ASSIGNMENT_DIRECT_EXPRESSION_FILE, AssignmentType.class); + assignmentType.setDescription(null); + user.asObjectable().getAssignment().add(assignmentType.clone()); + + // We need to make sure that the assignment has a parent + PrismContainerDefinition assignmentContainerDefinition = user.getDefinition().findContainerDefinition(UserType.F_ASSIGNMENT); + PrismContainer assignmentContainer = assignmentContainerDefinition.instantiate(); + assignmentContainer.add(assignmentType.asPrismContainerValue().clone()); + + ItemPath path = new ItemPath( + new NameItemPathSegment(UserType.F_ASSIGNMENT), + new IdItemPathSegment(123L), + new NameItemPathSegment(AssignmentType.F_DESCRIPTION)); + ObjectDelta userDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, USER_JACK_OID, + path, prismContext, "sailor"); + ObjectDeltaObject userOdo = new ObjectDeltaObject<>(user, userDelta, null); + userOdo.recompute(); + AssignmentEvaluator assignmentEvaluator = createAssignmentEvaluator(userOdo); + + ItemDeltaItem> assignmentIdi = new ItemDeltaItem<>(); + assignmentIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(assignmentType)); + assignmentIdi.setSubItemDeltas((Collection)userDelta.getModifications()); + assignmentIdi.recompute(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + EvaluatedAssignment evaluatedAssignment = assignmentEvaluator.evaluate(assignmentIdi, false, userTypeJack, "testDirect", task, result); + evaluatedAssignment.evaluateConstructions(userOdo, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertNotNull(evaluatedAssignment); + display("Evaluated assignment",evaluatedAssignment); + assertEquals(1,evaluatedAssignment.getConstructions().size()); + PrismAsserts.assertParentConsistency(user); + + Construction construction = evaluatedAssignment.getConstructions().iterator().next(); + assertNotNull("No object class definition in construction", construction.getRefinedObjectClassDefinition()); + assertEquals(1,construction.getAttributeMappings().size()); + Mapping> attributeMapping = (Mapping>) construction.getAttributeMappings().iterator().next(); + PrismValueDeltaSetTriple> outputTriple = attributeMapping.getOutputTriple(); + PrismAsserts.assertTripleNoZero(outputTriple); + PrismAsserts.assertTriplePlus(outputTriple, "The best sailor the world has ever seen"); + PrismAsserts.assertTripleMinus(outputTriple, "The best man the world has ever seen"); + + } + + private AssignmentEvaluator createAssignmentEvaluator() throws ObjectNotFoundException, SchemaException { + PrismObject userJack = userTypeJack.asPrismObject(); + return createAssignmentEvaluator(new ObjectDeltaObject(userJack, null, null)); + } + + private AssignmentEvaluator createAssignmentEvaluator(ObjectDeltaObject focusOdo) throws ObjectNotFoundException, SchemaException { + AssignmentEvaluator assignmentEvaluator = new AssignmentEvaluator<>(); + assignmentEvaluator.setRepository(repositoryService); + assignmentEvaluator.setFocusOdo(focusOdo); assignmentEvaluator.setObjectResolver(objectResolver); assignmentEvaluator.setPrismContext(prismContext); assignmentEvaluator.setActivationComputer(activationComputer); assignmentEvaluator.setNow(clock.currentTimeXMLGregorianCalendar()); + assignmentEvaluator.setMappingFactory(mappingFactory); + // Fake + assignmentEvaluator.setLensContext(new LensContext<>(UserType.class, prismContext, provisioningService)); return assignmentEvaluator; } - } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java index fd06adc47de..157c21cb599 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestProjector.java @@ -60,7 +60,9 @@ import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.delta.PropertyDelta; import com.evolveum.midpoint.prism.delta.ReferenceDelta; +import com.evolveum.midpoint.prism.path.IdItemPathSegment; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.path.NameItemPathSegment; import com.evolveum.midpoint.prism.util.PrismAsserts; import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; @@ -81,11 +83,14 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPolicyEnforcementType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; @@ -109,6 +114,7 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti super.initSystem(initTask, initResult); setDefaultUserTemplate(USER_TEMPLATE_OID); addObject(ORG_BRETHREN_FILE); + addObject(ROLE_MUTINIER_FILE); InternalMonitor.reset(); // InternalMonitor.setTraceShadowFetchOperation(true); } @@ -827,6 +833,54 @@ public void test275DeleteUserBarbossaAssignmentBrethren() throws Exception { assertNull(accContext.getPrimaryDelta()); assertEquals(SynchronizationPolicyDecision.KEEP,accContext.getSynchronizationPolicyDecision()); + } + + @Test + public void test280AddUserBarbossaAssignmentMutinier() throws Exception { + final String TEST_NAME = "test280AddUserBarbossaAssignmentMutinier"; + TestUtil.displayTestTile(this, TEST_NAME); + + // GIVEN + Task task = taskManager.createTaskInstance(TestProjector.class.getName() + "." + TEST_NAME); + + OperationResult result = task.getResult(); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.FULL); + + LensContext context = createUserAccountContext(); + fillContextWithUser(context, USER_BARBOSSA_OID, result); + fillContextWithAccount(context, ACCOUNT_HBARBOSSA_DUMMY_OID, result); + addFocusDeltaToContext(context, createAssignmentUserDelta(USER_BARBOSSA_OID, ROLE_MUTINIER_OID, + RoleType.COMPLEX_TYPE, null, null, true)); + context.recompute(); + + display("Input context", context); + + assertFocusModificationSanity(context); + + // WHEN + projector.project(context, "test", task, result); + + // THEN + display("Output context", context); + + assertTrue(context.getFocusContext().getPrimaryDelta().getChangeType() == ChangeType.MODIFY); + ObjectDelta userSecondaryDelta = context.getFocusContext().getSecondaryDelta(); + assertSideEffectiveDeltasOnly("user secondary delta", userSecondaryDelta); + + Collection accountContexts = context.getProjectionContexts(); + assertEquals(1, accountContexts.size()); + LensProjectionContext accContext = accountContexts.iterator().next(); + assertNull(accContext.getPrimaryDelta()); + assertEquals(SynchronizationPolicyDecision.KEEP,accContext.getSynchronizationPolicyDecision()); + + ObjectDelta accountSecondaryDelta = accContext.getSecondaryDelta(); + assertNotNull("No account secondary delta", accountSecondaryDelta); + assertEquals(ChangeType.MODIFY, accountSecondaryDelta.getChangeType()); + assertEquals("Unexpected number of account secondary changes", 1, accountSecondaryDelta.getModifications().size()); + PrismAsserts.assertPropertyAdd(accountSecondaryDelta, + dummyResourceCtl.getAttributePath(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME), + "Damned mutinier"); + PrismAsserts.assertOrigin(accountSecondaryDelta, OriginType.ASSIGNMENTS); } @Test diff --git a/model/model-impl/src/test/resources/lens/assignment-direct-expression.xml b/model/model-impl/src/test/resources/lens/assignment-direct-expression.xml new file mode 100644 index 00000000000..46cbf6c260c --- /dev/null +++ b/model/model-impl/src/test/resources/lens/assignment-direct-expression.xml @@ -0,0 +1,39 @@ + + + + + pirate + + + account + + ri:title + + + $assignment/description + + + + + + + + diff --git a/model/model-impl/src/test/resources/lens/role-mutinier.xml b/model/model-impl/src/test/resources/lens/role-mutinier.xml new file mode 100644 index 00000000000..4d23abf5a8e --- /dev/null +++ b/model/model-impl/src/test/resources/lens/role-mutinier.xml @@ -0,0 +1,48 @@ + + + Mutinier + + + + account + + ri:title + + + $assignment/description + + + + + + + + + + http://midpoint.evolveum.com/xml/ns/test/authorization#loot + + true + diff --git a/model/model-impl/src/test/resources/lens/role-pirate.xml b/model/model-impl/src/test/resources/lens/role-pirate.xml index 765f9b187ef..4e513491d78 100644 --- a/model/model-impl/src/test/resources/lens/role-pirate.xml +++ b/model/model-impl/src/test/resources/lens/role-pirate.xml @@ -17,7 +17,7 @@ xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3" xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3" xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3" - xmlns:ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance/10000000-0000-0000-0000-000000000004" + xmlns:ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance-3" xmlns:piracy="http://midpoint.evolveum.com/xml/ns/samples/piracy"> Pirate Bloody pirates diff --git a/model/model-impl/src/test/resources/logback-test.xml b/model/model-impl/src/test/resources/logback-test.xml index afaead0e3db..0ecab1aec8c 100644 --- a/model/model-impl/src/test/resources/logback-test.xml +++ b/model/model-impl/src/test/resources/logback-test.xml @@ -31,7 +31,7 @@ - + diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java index 4cd0c7750b2..d2951c4c96e 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java @@ -43,6 +43,9 @@ import com.evolveum.midpoint.prism.PrismPropertyDefinition; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.IdItemPathSegment; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.path.NameItemPathSegment; import com.evolveum.midpoint.prism.query.EqualFilter; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; @@ -58,6 +61,7 @@ import com.evolveum.midpoint.test.util.TestUtil; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentPolicyEnforcementType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; @@ -84,6 +88,9 @@ public class TestRbac extends AbstractInitializedModelIntegrationTest { protected static final File ROLE_HONORABILITY_FILE = new File(TEST_DIR, "role-honorability.xml"); protected static final String ROLE_HONORABILITY_OID = "12345678-d34d-b33f-f00d-555555557701"; + + protected static final File ROLE_CLERIC_FILE = new File(TEST_DIR, "role-cleric.xml"); + protected static final String ROLE_CLERIC_OID = "12345678-d34d-b33f-f00d-555555557702"; private final String EXISTING_GOSSIP = "Black spot!"; @@ -101,6 +108,7 @@ public void initSystem(Task initTask, OperationResult initResult) repoAddObjectFromFile(ROLE_BLACK_SEA_PIRATE_FILE, RoleType.class, initResult); repoAddObjectFromFile(ROLE_INDIAN_OCEAN_PIRATE_FILE, RoleType.class, initResult); repoAddObjectFromFile(ROLE_HONORABILITY_FILE, RoleType.class, initResult); + repoAddObjectFromFile(ROLE_CLERIC_FILE, RoleType.class, initResult); } @Test @@ -946,6 +954,88 @@ public void test521JackUnassignRolePirateDeleteAccount() throws Exception { assertNoDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME); } + @Test + public void test530JackAssignRoleCleric() throws Exception { + final String TEST_NAME = "test530JackAssignRoleCleric"; + TestUtil.displayTestTile(this, TEST_NAME); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + assignRole(USER_JACK_OID, ROLE_CLERIC_OID, task, result); + + // THEN + assertAssignedRole(USER_JACK_OID, ROLE_CLERIC_OID, task, result); + assertDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME, ACCOUNT_JACK_DUMMY_FULLNAME, true); + assertDefaultDummyAccountAttribute(ACCOUNT_JACK_DUMMY_USERNAME, "title", "Holy man"); + } + + @Test + public void test532JackModifyAssignmentRoleCleric() throws Exception { + final String TEST_NAME = "test532JackModifyAssignmentRoleCleric"; + TestUtil.displayTestTile(this, TEST_NAME); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + PrismObject user = getObject(UserType.class, USER_JACK_OID); + + ItemPath itemPath = new ItemPath( + new NameItemPathSegment(UserType.F_ASSIGNMENT), + new IdItemPathSegment(user.asObjectable().getAssignment().get(0).getId()), + new NameItemPathSegment(AssignmentType.F_DESCRIPTION)); + ObjectDelta assignmentDelta = ObjectDelta.createModificationReplaceProperty( + UserType.class, USER_JACK_OID, itemPath, prismContext, "soul"); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modelService.executeChanges(MiscSchemaUtil.createCollection(assignmentDelta), null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertAssignedRole(USER_JACK_OID, ROLE_CLERIC_OID, task, result); + assertDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME, ACCOUNT_JACK_DUMMY_FULLNAME, true); + assertDefaultDummyAccountAttribute(ACCOUNT_JACK_DUMMY_USERNAME, "title", "Holy soul"); + } + + @Test + public void test539JackUnAssignRoleCleric() throws Exception { + final String TEST_NAME = "test539JackUnAssignRoleCleric"; + TestUtil.displayTestTile(this, TEST_NAME); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + PrismObject user = getObject(UserType.class, USER_JACK_OID); + + AssignmentType assignmentType = new AssignmentType(); + assignmentType.setId(user.asObjectable().getAssignment().get(0).getId()); + ObjectDelta assignmentDelta = ObjectDelta.createModificationDeleteContainer( + UserType.class, USER_JACK_OID, UserType.F_ASSIGNMENT, prismContext, assignmentType); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modelService.executeChanges(MiscSchemaUtil.createCollection(assignmentDelta), null, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + PrismObject userJack = getUser(USER_JACK_OID); + display("User after", userJack); + assertAssignedNoRole(userJack); + assertNoLinkedAccount(userJack); + assertNoDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME); + } + @Test public void test600JackAssignRoleJudge() throws Exception { final String TEST_NAME = "test600JackAssignRoleJudge"; diff --git a/model/model-intest/src/test/resources/logback-test.xml b/model/model-intest/src/test/resources/logback-test.xml index 4b8726a3414..40ea96b1382 100644 --- a/model/model-intest/src/test/resources/logback-test.xml +++ b/model/model-intest/src/test/resources/logback-test.xml @@ -58,7 +58,7 @@ - + diff --git a/model/model-intest/src/test/resources/rbac/role-cleric.xml b/model/model-intest/src/test/resources/rbac/role-cleric.xml new file mode 100644 index 00000000000..d38e7f0d883 --- /dev/null +++ b/model/model-intest/src/test/resources/rbac/role-cleric.xml @@ -0,0 +1,43 @@ + + + Cleric + + + + account + + ri:title + + + $assignment/description + + + + + + + + + diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceManager.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceManager.java index b8048733e5f..53e2fec54f3 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceManager.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceManager.java @@ -37,6 +37,7 @@ import com.evolveum.midpoint.prism.ComplexTypeDefinition; import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.Definition; +import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContainerDefinition; @@ -879,8 +880,9 @@ public void applyDefinition(ObjectDelta delta, ResourceType resour ReferenceDelta connectorRefDelta = ReferenceDelta.findReferenceModification(delta.getModifications(), ResourceType.F_CONNECTOR_REF); if (connectorRefDelta != null){ - if (connectorRefDelta.getItemNew().getValues().size() == 1){ - PrismReferenceValue connectorRefValue = connectorRefDelta.getItemNew().getValues().iterator().next(); + Item connectorRefNew = connectorRefDelta.getItemNewMatchingPath(null); + if (connectorRefNew.getValues().size() == 1){ + PrismReferenceValue connectorRefValue = connectorRefNew.getValues().iterator().next(); if (connectorRefValue.getOid() != null && !connectorOid.equals(connectorRefValue.getOid())){ connectorOid = connectorRefValue.getOid(); } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java index 04f1d9310cf..e93d07d4166 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java @@ -779,7 +779,7 @@ private Collection determineActivationChange(ShadowType shadow, Colle if (activationCapabilityType == null) { throw new SchemaException("Attempt to change activation administrativeStatus on "+resource+" which does not have the capability"); } - ActivationStatusType status = enabledPropertyDelta.getPropertyNew().getRealValue(); + ActivationStatusType status = enabledPropertyDelta.getPropertyNewMatchingPath().getRealValue(); LOGGER.trace("Found activation administrativeStatus change to: {}", status); // if (status != null) { @@ -804,7 +804,7 @@ private Collection determineActivationChange(ShadowType shadow, Colle if (activationCapabilityType == null || activationCapabilityType.getValidFrom() == null) { throw new SchemaException("Attempt to change activation validFrom on "+resource+" which does not have the capability"); } - XMLGregorianCalendar xmlCal = validFromPropertyDelta.getPropertyNew().getRealValue(); + XMLGregorianCalendar xmlCal = validFromPropertyDelta.getPropertyNewMatchingPath().getRealValue(); LOGGER.trace("Found activation validFrom change to: {}", xmlCal); operations.add(new PropertyModificationOperation(validFromPropertyDelta)); } @@ -816,7 +816,7 @@ private Collection determineActivationChange(ShadowType shadow, Colle if (activationCapabilityType == null || activationCapabilityType.getValidTo() == null) { throw new SchemaException("Attempt to change activation validTo on "+resource+" which does not have the capability"); } - XMLGregorianCalendar xmlCal = validToPropertyDelta.getPropertyNew().getRealValue(); + XMLGregorianCalendar xmlCal = validToPropertyDelta.getPropertyNewMatchingPath().getRealValue(); LOGGER.trace("Found activation validTo change to: {}", xmlCal); operations.add(new PropertyModificationOperation(validToPropertyDelta)); } @@ -827,7 +827,7 @@ private Collection determineActivationChange(ShadowType shadow, Colle if (activationCapabilityType == null) { throw new SchemaException("Attempt to change activation lockoutStatus on "+resource+" which does not have the capability"); } - LockoutStatusType status = lockoutPropertyDelta.getPropertyNew().getRealValue(); + LockoutStatusType status = lockoutPropertyDelta.getPropertyNewMatchingPath().getRealValue(); LOGGER.trace("Found activation lockoutStatus change to: {}", status); if (ResourceTypeUtil.hasResourceNativeActivationLockoutCapability(resource)) { @@ -859,7 +859,7 @@ private void checkSimulatedActivationAdministrativeStatus(Collection> distillRenameDeltas(Collection name = nameDelta.getPropertyNew(); + PrismProperty name = nameDelta.getPropertyNewMatchingPath(); String newName = name.getRealValue(); Collection> deltas = new ArrayList>(); diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java index bced2152cb6..4dd73ca9896 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java @@ -2217,7 +2217,7 @@ private void convertFromActivation(Set updateAttributes, } private T getPropertyNewValue(PropertyDelta propertyDelta, Class clazz) throws SchemaException { - PrismProperty> prop = propertyDelta.getPropertyNew(); + PrismProperty> prop = propertyDelta.getPropertyNewMatchingPath(); if (prop == null){ return null; } @@ -2243,7 +2243,7 @@ private void convertFromPassword(Set attributes, PropertyDelta newPassword = passwordDelta.getPropertyNew(); + PrismProperty newPassword = passwordDelta.getPropertyNewMatchingPath(); if (newPassword == null || newPassword.isEmpty()) { LOGGER.trace("Skipping processing password delta. Password delta does not contain new value."); return; From e7b9f62fc4305304d5398cb434c6ba3240f230b7 Mon Sep 17 00:00:00 2001 From: "Katarina Valalikova (katkav)" Date: Wed, 30 Jul 2014 11:04:41 +0200 Subject: [PATCH 37/51] fixing MID-2013 (setting corrent value for intent while recociling, process also (newly created) shadows without intent).. --- .../RefinedObjectClassDefinition.java | 17 +++-- .../impl/sync/SynchronizationService.java | 74 +++++++++++++++---- .../midpoint/model/impl/util/Utils.java | 2 +- 3 files changed, 69 insertions(+), 24 deletions(-) diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedObjectClassDefinition.java b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedObjectClassDefinition.java index 5cc3d3b8db8..12517f5c97b 100644 --- a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedObjectClassDefinition.java +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedObjectClassDefinition.java @@ -768,15 +768,16 @@ public boolean matches(ShadowType shadowType) { return false; } } - if (shadowType.getIntent() == null) { - if (isDefault) { - return true; - } else { - return false; - } - } else { + if (shadowType.getIntent() != null) { +// if (isDefault) { +// return true; +// } else { +// return false; +// } +// } else { return MiscUtil.equals(intent, shadowType.getIntent()); - } + } + return true; } @Override diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java index 1fa13c97793..a194ae65e62 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/sync/SynchronizationService.java @@ -47,6 +47,7 @@ import com.evolveum.midpoint.model.common.expression.ExpressionVariables; import com.evolveum.midpoint.model.common.expression.Source; import com.evolveum.midpoint.model.common.expression.StringPolicyResolver; +import com.evolveum.midpoint.model.impl.ModelConstants; import com.evolveum.midpoint.model.impl.controller.ModelController; import com.evolveum.midpoint.model.impl.lens.Clockwork; import com.evolveum.midpoint.model.impl.lens.ContextFactory; @@ -174,22 +175,20 @@ public void notifyChange(ResourceObjectShadowChangeDescription change, Task task OperationResult subResult = parentResult.createSubresult(NOTIFY_CHANGE); try { - ResourceType resourceType = change.getResource().asObjectable(); + PrismObject currentShadow = change.getCurrentShadow(); - if (currentShadow != null) { - ShadowType currentShadowType = currentShadow.asObjectable(); - if (currentShadowType.isProtectedObject() != null && currentShadowType.isProtectedObject()) { - LOGGER.trace("SYNCHRONIZATION skipping {} because it is protected", currentShadowType); - // Just make sure there is no misleading synchronization situation in the shadow - if (currentShadowType.getSynchronizationSituation() != null) { - ObjectDelta shadowDelta = ObjectDelta.createModificationReplaceProperty(ShadowType.class, currentShadowType.getOid(), - ShadowType.F_SYNCHRONIZATION_SITUATION, prismContext); - provisioningService.modifyObject(ShadowType.class, currentShadowType.getOid(), - shadowDelta.getModifications(), null, null, task, subResult); - } - subResult.recordStatus(OperationResultStatus.NOT_APPLICABLE, "Skipped because it is protected"); - return; + + if (isProtected((PrismObject) currentShadow)){ + LOGGER.trace("SYNCHRONIZATION skipping {} because it is protected", currentShadow); + // Just make sure there is no misleading synchronization situation in the shadow + if (currentShadow.asObjectable().getSynchronizationSituation() != null) { + ObjectDelta shadowDelta = ObjectDelta.createModificationReplaceProperty(ShadowType.class, currentShadow.getOid(), + ShadowType.F_SYNCHRONIZATION_SITUATION, prismContext); + provisioningService.modifyObject(ShadowType.class, currentShadow.getOid(), + shadowDelta.getModifications(), null, null, task, subResult); } + subResult.recordStatus(OperationResultStatus.NOT_APPLICABLE, "Skipped because it is protected"); + return; } PrismObject applicableShadow = currentShadow; @@ -198,6 +197,7 @@ public void notifyChange(ResourceObjectShadowChangeDescription change, Task task applicableShadow = change.getOldShadow(); } + ResourceType resourceType = change.getResource().asObjectable(); PrismObject configuration = Utils.getSystemConfiguration(repositoryService, subResult); ObjectSynchronizationType synchronizationPolicy = determineSynchronizationPolicy(resourceType, @@ -210,7 +210,7 @@ public void notifyChange(ResourceObjectShadowChangeDescription change, Task task subResult.recordStatus(OperationResultStatus.NOT_APPLICABLE, message); return; } - + if (!isSynchronizationEnabled(synchronizationPolicy)) { String message = "SYNCHRONIZATION is not enabled for " + resourceType + " ignoring change from channel " + change.getSourceChannel(); @@ -219,6 +219,14 @@ public void notifyChange(ResourceObjectShadowChangeDescription change, Task task return; } + //check if the kind/intent in the syncPolicy satisfy constaints defined in task + if (!satisfyTaskConstaints(synchronizationPolicy, task)){ + LOGGER.trace("SYNCHRONIZATION skipping {} because it does not match kind/intent defined in task",new Object[] { + applicableShadow}); + subResult.recordStatus(OperationResultStatus.NOT_APPLICABLE, "Skipped because it does not match objectClass/kind/intent"); + return; + } + Class focusType = determineFocusClass(synchronizationPolicy, resourceType); if (LOGGER.isTraceEnabled()) { @@ -272,6 +280,42 @@ public void notifyChange(ResourceObjectShadowChangeDescription change, Task task } } + private boolean satisfyTaskConstaints(ObjectSynchronizationType synchronizationPolicy, Task task) { + PrismProperty kind = task.getExtensionProperty(SchemaConstants.MODEL_EXTENSION_KIND); + if (kind != null && !kind.isEmpty()){ + ShadowKindType kindValue = kind.getRealValue(); + if (!synchronizationPolicy.getKind().equals(kindValue)){ + return false; + } + } + + PrismProperty intent = task.getExtensionProperty(SchemaConstants.MODEL_EXTENSION_INTENT); + if (intent != null && !intent.isEmpty()){ + String intentValue = intent.getRealValue(); + if (StringUtils.isEmpty(synchronizationPolicy.getIntent())){ + return false; + } + if (!synchronizationPolicy.getIntent().equals(intentValue)){ + return false; + } + } + + return true; + } + + private boolean isProtected(PrismObject shadow){ + if (shadow == null){ + return false; + } + + ShadowType currentShadowType = shadow.asObjectable(); + if (currentShadowType.isProtectedObject() == null){ + return false; + } + + return currentShadowType.isProtectedObject(); + } + private Class determineFocusClass(ObjectSynchronizationType synchronizationPolicy, ResourceType resource) throws ConfigurationException { QName focusTypeQName = synchronizationPolicy.getFocusType(); if (focusTypeQName == null) { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java index 4d0cbab6d70..ef05bed4c04 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/Utils.java @@ -392,7 +392,7 @@ public static boolean isDryRun(Task task) throws SchemaException{ return false; } - PrismProperty item = task.getExtension().findProperty(SchemaConstants.MODEL_EXTENSION_DRY_RUN); + PrismProperty item = task.getExtensionProperty(SchemaConstants.MODEL_EXTENSION_DRY_RUN); if (item == null || item.isEmpty()){ return false; } From 1c579c7a250ea88dc841600373f0c10764b59ed8 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 30 Jul 2014 11:29:55 +0200 Subject: [PATCH 38/51] Fixes after refactoring. --- .../com/evolveum/midpoint/prism/delta/ItemDelta.java | 9 ++++++++- .../provisioning/impl/ResourceObjectConverter.java | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java index 5f9e35a3390..687fd94d5cd 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java @@ -936,6 +936,13 @@ public static void applyTo(Collection deltas, PrismContaine } } + public static void applyToMatchingPath(Collection deltas, PrismContainer propertyContainer) + throws SchemaException { + for (ItemDelta delta : deltas) { + delta.applyToMatchingPath(propertyContainer); + } + } + public void applyTo(Item item) throws SchemaException { ItemPath itemPath = item.getPath(); ItemPath deltaPath = getPath(); @@ -947,7 +954,7 @@ public void applyTo(Item item) throws SchemaException { if (item instanceof PrismContainer) { PrismContainer container = (PrismContainer)item; ItemPath remainderPath = deltaPath.remainder(itemPath); - Item subItem = container.findOrCreateItem(remainderPath, getItemClass()); + Item subItem = container.findOrCreateItem(remainderPath, getItemClass(), getDefinition()); applyToMatchingPath(subItem); } else { throw new SchemaException("Cannot apply delta "+this+" to "+item+" as delta path is below the item path and the item is not a container"); diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java index ded18a741af..5559df0a915 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectConverter.java @@ -625,7 +625,7 @@ private Collection distillRenameDeltas(Collection return null; } - PrismProperty name = nameDelta.getPropertyNew(); + PrismProperty name = nameDelta.getPropertyNewMatchingPath(); String newName = name.getRealValue(); Collection deltas = new ArrayList(); From 762b0bbcd63036f993552b9f15925937b58e6534 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 30 Jul 2014 14:13:01 +0200 Subject: [PATCH 39/51] Assignment evaluation refactoring in progress. --- .../midpoint/prism/delta/DeltaMapTriple.java | 308 ++++++++++++++++++ .../midpoint/prism/delta/PlusMinusZero.java | 24 ++ .../model/impl/lens/AssignmentEvaluator.java | 2 +- .../model/impl/lens/EvaluatedAssignment.java | 21 +- .../lens/projector/AssignmentProcessor.java | 129 +++++--- .../impl/lens/TestAssignmentEvaluator.java | 8 +- 6 files changed, 425 insertions(+), 67 deletions(-) create mode 100644 infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/DeltaMapTriple.java diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/DeltaMapTriple.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/DeltaMapTriple.java new file mode 100644 index 00000000000..ccbbd5baeb0 --- /dev/null +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/DeltaMapTriple.java @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2010-2014 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.prism.delta; + +import com.evolveum.midpoint.prism.SimpleVisitable; +import com.evolveum.midpoint.prism.SimpleVisitor; +import com.evolveum.midpoint.prism.Visitable; +import com.evolveum.midpoint.prism.Visitor; +import com.evolveum.midpoint.util.Cloner; +import com.evolveum.midpoint.util.DebugDumpable; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.util.MiscUtil; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +/** + * + * @author Radovan Semancik + */ +public class DeltaMapTriple implements DebugDumpable, Serializable, SimpleVisitable> { + + /** + * Collection of values that were not changed. + */ + protected Map zeroMap; + + /** + * Collection of values that were added. + */ + protected Map plusMap; + + /** + * Collection of values that were deleted. + */ + protected Map minusMap; + + public DeltaMapTriple() { + zeroMap = createMap(); + plusMap = createMap(); + minusMap = createMap(); + } + + public DeltaMapTriple(Map zeroMap, Map plusMap, Map minusMap) { + this.zeroMap = zeroMap; + this.plusMap = plusMap; + this.minusMap = minusMap; + } + + protected Map createMap() { + return new HashMap<>(); + } + + public Map getZeroMap() { + return zeroMap; + } + + public Map getPlusMap() { + return plusMap; + } + + public Map getMinusMap() { + return minusMap; + } + + public Map getMap(PlusMinusZero plusMinusZero) { + if (plusMinusZero == null) { + return null; + } + switch (plusMinusZero) { + case PLUS: return plusMap; + case MINUS: return minusMap; + case ZERO: return zeroMap; + } + // notreached + throw new IllegalStateException(); + } + + public boolean hasPlusMap() { + return (plusMap != null && !plusMap.isEmpty()); + } + + public boolean hasZeroMap() { + return (zeroMap != null && !zeroMap.isEmpty()); + } + + public boolean hasMinusMap() { + return (minusMap != null && !minusMap.isEmpty()); + } + + public boolean isZeroOnly() { + return hasZeroMap() && !hasPlusMap() && !hasMinusMap(); + } + + public void addToPlusMap(K key, V value) { + addToMap(plusMap, key, value); + } + + public void addToMinusMap(K key, V value) { + addToMap(minusMap, key, value); + } + + public void addToZeroMap(K key, V value) { + addToMap(zeroMap, key, value); + } + + public void addAllToPlusMap(Map map) { + addAllToMap(plusMap, map); + } + + public void addAllToMinusMap(Map map) { + addAllToMap(minusMap, map); + } + + public void addAllToZeroMap(Map map) { + addAllToMap(zeroMap, map); + + } + + public void addAllToMap(PlusMinusZero destination, Map map) { + if (destination == null) { + return; + } else if (destination == PlusMinusZero.PLUS) { + addAllToMap(plusMap, map); + } else if (destination == PlusMinusZero.MINUS) { + addAllToMap(minusMap, map); + } else if (destination == PlusMinusZero.ZERO) { + addAllToMap(zeroMap, map); + } + } + + private void addAllToMap(Map set, Map items) { + if (items == null) { + return; + } + for (Entry item: items.entrySet()) { + addToMap(set, item.getKey(), item.getValue()); + } + } + + private void addToMap(Map set, K key, V value) { + if (set == null) { + set = createMap(); + } + set.put(key, value); + } + + public void clearPlusMap() { + clearMap(plusMap); + } + + public void clearMinusMap() { + clearMap(minusMap); + } + + public void clearZeroMap() { + clearMap(zeroMap); + } + + private void clearMap(Map set) { + if (set != null) { + set.clear(); + } + } + + public int size() { + return sizeMap(zeroMap) + sizeMap(plusMap) + sizeMap(minusMap); + } + + private int sizeMap(Map set) { + if (set == null) { + return 0; + } + return set.size(); + } + + public void merge(DeltaMapTriple triple) { + addAllToZeroMap(triple.zeroMap); + addAllToPlusMap(triple.plusMap); + addAllToMinusMap(triple.minusMap); + } + + /** + * Returns all values, regardless of the internal sets. + */ + public Collection unionKeySets() { + return MiscUtil.union(zeroMap.keySet(), plusMap.keySet(), minusMap.keySet()); + } + + public DeltaMapTriple clone(Cloner> cloner) { + DeltaMapTriple clone = new DeltaMapTriple(); + copyValues(clone, cloner); + return clone; + } + + protected void copyValues(DeltaMapTriple clone, Cloner> cloner) { + clone.zeroMap = cloneSet(this.zeroMap, cloner); + clone.plusMap = cloneSet(this.plusMap, cloner); + clone.minusMap = cloneSet(this.minusMap, cloner); + } + + private Map cloneSet(Map origSet, Cloner> cloner) { + if (origSet == null) { + return null; + } + Map clonedSet = createMap(); + for (Entry origVal: origSet.entrySet()) { + Entry clonedVal = cloner.clone(origVal); + clonedSet.put(clonedVal.getKey(), clonedVal.getValue()); + } + return clonedSet; + } + + public boolean isEmpty() { + return isEmpty(minusMap) && isEmpty(plusMap) && isEmpty(zeroMap); + } + + private boolean isEmpty(Map set) { + if (set == null) { + return true; + } + return set.isEmpty(); + } + + @Override + public void accept(SimpleVisitor> visitor) { + acceptMap(visitor, zeroMap); + acceptMap(visitor, plusMap); + acceptMap(visitor, minusMap); + } + + private void acceptMap(SimpleVisitor> visitor, Map set) { + if (set == null) { + return; + } + for (Entry element: set.entrySet()) { + visitor.visit(element); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(debugName()).append("("); + dumpMap(sb, "zero", zeroMap); + dumpMap(sb, "plus", plusMap); + dumpMap(sb, "minus", minusMap); + sb.append(")"); + return sb.toString(); + } + + protected String debugName() { + return "DeltaMapTriple"; + } + + private void dumpMap(StringBuilder sb, String label, Map set) { + sb.append(label).append(": ").append(set).append("; "); + } + + /* (non-Javadoc) + * @see com.evolveum.midpoint.util.DebugDumpable#debugDump() + */ + @Override + public String debugDump() { + return debugDump(0); + } + + /* (non-Javadoc) + * @see com.evolveum.midpoint.util.DebugDumpable#debugDump(int) + */ + @Override + public String debugDump(int indent) { + StringBuilder sb = new StringBuilder(); + DebugUtil.indentDebugDump(sb, indent); + sb.append("DeltaSetTriple:\n"); + debugDumpMap(sb, "zero", zeroMap, indent + 1); + sb.append("\n"); + debugDumpMap(sb, "plus", plusMap, indent + 1); + sb.append("\n"); + debugDumpMap(sb, "minus", minusMap, indent + 1); + return sb.toString(); + } + + private void debugDumpMap(StringBuilder sb, String label, Map set, int indent) { + DebugUtil.debugDumpLabel(sb, label, indent); + sb.append("\n"); + DebugUtil.debugDumpMapMultiLine(sb, set, indent + 1); + } + +} diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/PlusMinusZero.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/PlusMinusZero.java index e434e2e4c06..6473bdbb3cb 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/PlusMinusZero.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/PlusMinusZero.java @@ -26,4 +26,28 @@ public enum PlusMinusZero { PLUS, MINUS, ZERO; + public static PlusMinusZero compute(PlusMinusZero mode1, PlusMinusZero mode2) { + if (mode1 == null || mode2 == null) { + return null; + } + switch (mode1) { + case PLUS: switch (mode2) { + case PLUS: return PlusMinusZero.PLUS; + case ZERO: return PlusMinusZero.PLUS; + case MINUS: return null; + } + case ZERO: switch (mode2) { + case PLUS: return PlusMinusZero.PLUS; + case ZERO: return PlusMinusZero.ZERO; + case MINUS: return PlusMinusZero.MINUS; + } + case MINUS: switch (mode2) { + case PLUS: return null; + case ZERO: return PlusMinusZero.MINUS; + case MINUS: return PlusMinusZero.MINUS; + } + } + // notreached + throw new IllegalStateException(); + } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java index 8745b881073..2241e8ada69 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java @@ -290,7 +290,7 @@ private void prepareConstructionEvaluation(EvaluatedAssignment evaluatedAssig // Do not evaluate the construction here. We will do it in the second pass. Just prepare everything to be evaluated. - evaluatedAssignment.addConstruction(construction); + evaluatedAssignment.addConstructionZero(construction); } private void evaluateFocusMappings(EvaluatedAssignment evaluatedAssignment, AssignmentPathSegment assignmentPathSegment, diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java index 8cf2b64bea6..b78881a96f3 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java @@ -25,6 +25,7 @@ import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.delta.DeltaSetTriple; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.Authorization; import com.evolveum.midpoint.task.api.Task; @@ -51,7 +52,7 @@ public class EvaluatedAssignment implements DebugDumpable { private static final Trace LOGGER = TraceManager.getTrace(EvaluatedAssignment.class); private ItemDeltaItem> assignmentIdi; - private Collection> constructions; + private DeltaSetTriple> constructions; private Collection orgRefVals; private Collection authorizations; private Collection>> focusMappings; @@ -60,7 +61,7 @@ public class EvaluatedAssignment implements DebugDumpable { private boolean forceRecon; public EvaluatedAssignment() { - constructions = new ArrayList<>(); + constructions = new DeltaSetTriple<>(); orgRefVals = new ArrayList<>(); authorizations = new ArrayList<>(); focusMappings = new ArrayList<>(); @@ -78,12 +79,12 @@ public AssignmentType getAssignmentType() { return assignmentIdi.getItemNew().getValue(0).asContainerable(); } - public Collection> getConstructions() { + public DeltaSetTriple> getConstructions() { return constructions; } - public void addConstruction(Construction contruction) { - constructions.add(contruction); + public void addConstructionZero(Construction contruction) { + constructions.addToZeroSet(contruction); } public Collection getOrgRefVals() { @@ -136,14 +137,14 @@ public void setForceRecon(boolean forceRecon) { public Collection getResources(OperationResult result) throws ObjectNotFoundException, SchemaException { Collection resources = new ArrayList(); - for (Construction acctConstr: constructions) { + for (Construction acctConstr: constructions.getAllValues()) { resources.add(acctConstr.getResource(result)); } return resources; } public void evaluateConstructions(ObjectDeltaObject focusOdo, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException { - for (Construction construction :constructions) { + for (Construction construction :constructions.getAllValues()) { construction.setFocusOdo(focusOdo); LOGGER.trace("Evaluating construction '{}' in {}", construction, construction.getSource()); construction.evaluate(task, result); @@ -163,11 +164,7 @@ public String debugDump(int indent) { DebugUtil.debugDumpWithLabel(sb, "isValid", isValid, indent + 1); if (!constructions.isEmpty()) { sb.append("\n"); - DebugUtil.debugDumpLabel(sb, "Constructions", indent+1); - for (Construction ac: constructions) { - sb.append("\n"); - sb.append(ac.debugDump(indent+2)); - } + DebugUtil.debugDumpWithLabel(sb, "Constructions", constructions, indent+1); } if (!orgRefVals.isEmpty()) { sb.append("\n"); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java index ce27e55b016..ae713857148 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java @@ -41,6 +41,7 @@ import com.evolveum.midpoint.model.impl.lens.LensUtil; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ContainerDelta; +import com.evolveum.midpoint.prism.delta.DeltaMapTriple; import com.evolveum.midpoint.prism.delta.DeltaSetTriple; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; @@ -207,11 +208,9 @@ private void processAssignmentsProjectionsWithFocus(LensCo assignmentEvaluator.setNow(now); assignmentEvaluator.setSystemConfiguration(context.getSystemConfiguration()); - // We will be collecting the evaluated account constructions into these three sets. + // We will be collecting the evaluated account constructions into these three maps. // It forms a kind of delta set triple for the account constructions. - Map zeroConstructionMap = new HashMap(); - Map plusConstructionMap = new HashMap(); - Map minusConstructionMap = new HashMap(); + DeltaMapTriple constructionMapTriple = new DeltaMapTriple<>(); LOGGER.trace("Current assignments {}", SchemaDebugUtil.prettyPrint(assignmentsCurrent)); LOGGER.trace("Changed assignments {}", SchemaDebugUtil.prettyPrint(changedAssignments)); @@ -456,14 +455,11 @@ private void processAssignmentsProjectionsWithFocus(LensCo // because there may be interaction from focusMappings of some roles to outbound mappings of other roles. // Now we have complete focus with all the focusMappings so we can evaluate the constructions evaluateConstructions(context, evaluatedAssignmentTriple, task, result); - collectToConstructionMap(context, evaluatedAssignmentTriple.getZeroSet(), zeroConstructionMap, result); - collectToConstructionMap(context, evaluatedAssignmentTriple.getPlusSet(), plusConstructionMap, result); - collectToConstructionMap(context, evaluatedAssignmentTriple.getMinusSet(), minusConstructionMap, result); + collectToConstructionMaps(context, evaluatedAssignmentTriple, constructionMapTriple, result); if (LOGGER.isTraceEnabled()) { // Dump the maps - LOGGER.trace("Projection maps:\nZERO:\n{}\nPLUS:\n{}\nMINUS:\n{}\n", new Object[]{dumpAccountMap(zeroConstructionMap), - dumpAccountMap(plusConstructionMap), dumpAccountMap(minusConstructionMap)}); + LOGGER.trace("Projection maps:\n{}", constructionMapTriple.debugDump()); } // Now we are processing constructions from all the three sets once again. We will create projection contexts @@ -471,7 +467,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo // I.e. zero means unchanged, plus means added, minus means deleted. That will be recorded in the SynchronizationPolicyDecision. // We will also collect all the construction triples to projection context. These will be used later for computing // actual attribute deltas (in consolidation processor). - Collection allAccountTypes = MiscUtil.union(zeroConstructionMap.keySet(), plusConstructionMap.keySet(), minusConstructionMap.keySet()); + Collection allAccountTypes = constructionMapTriple.unionKeySets(); for (ResourceShadowDiscriminator rat : allAccountTypes) { if (rat.getResourceOid() == null) { @@ -483,7 +479,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo String desc = rat.toHumanReadableString(); // SITUATION: The projection should exist (if valid), there is NO CHANGE in assignments - if (zeroConstructionMap.containsKey(rat)) { + if (constructionMapTriple.getZeroMap().containsKey(rat)) { LensProjectionContext projectionContext = context.findProjectionContext(rat); if (projectionContext == null) { @@ -492,7 +488,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo // Pretend that the assignment was just added. That should do. projectionContext = LensUtil.getOrCreateProjectionContext(context, rat); } - ConstructionPack constructionPack = zeroConstructionMap.get(rat); + ConstructionPack constructionPack = constructionMapTriple.getZeroMap().get(rat); if (constructionPack.hasValidAssignment()) { LOGGER.trace("Projection {} legal: unchanged (valid)", desc); projectionContext.setLegal(true); @@ -507,13 +503,13 @@ private void processAssignmentsProjectionsWithFocus(LensCo // SITUATION: The projection is both ASSIGNED and UNASSIGNED - } else if (plusConstructionMap.containsKey(rat) && minusConstructionMap.containsKey(rat)) { + } else if (constructionMapTriple.getPlusMap().containsKey(rat) && constructionMapTriple.getMinusMap().containsKey(rat)) { // Account was removed and added in the same operation. This is the case if e.g. one role is // removed and another is added and they include the same account. // Keep original account state - ConstructionPack plusPack = plusConstructionMap.get(rat); - ConstructionPack minusPack = minusConstructionMap.get(rat); + ConstructionPack plusPack = constructionMapTriple.getPlusMap().get(rat); + ConstructionPack minusPack = constructionMapTriple.getMinusMap().get(rat); if (plusPack.hasValidAssignment() && minusPack.hasValidAssignment()) { @@ -573,9 +569,9 @@ private void processAssignmentsProjectionsWithFocus(LensCo // SITUATION: The projection is ASSIGNED - } else if (plusConstructionMap.containsKey(rat)) { + } else if (constructionMapTriple.getPlusMap().containsKey(rat)) { - ConstructionPack constructionPack = plusConstructionMap.get(rat); + ConstructionPack constructionPack = constructionMapTriple.getPlusMap().get(rat); if (constructionPack.hasValidAssignment()) { LensProjectionContext projectionContext = LensUtil.getOrCreateProjectionContext(context, rat); projectionContext.setAssigned(true); @@ -591,7 +587,7 @@ private void processAssignmentsProjectionsWithFocus(LensCo } // SITUATION: The projection is UNASSIGNED - } else if (minusConstructionMap.containsKey(rat)) { + } else if (constructionMapTriple.getMinusMap().containsKey(rat)) { if (accountExists(context,rat)) { LensProjectionContext projectionContext = LensUtil.getOrCreateProjectionContext(context, rat); @@ -620,14 +616,14 @@ private void processAssignmentsProjectionsWithFocus(LensCo PrismValueDeltaSetTriple> accountDeltaSetTriple = new PrismValueDeltaSetTriple>( - getConstructions(zeroConstructionMap.get(rat)), - getConstructions(plusConstructionMap.get(rat)), - getConstructions(minusConstructionMap.get(rat))); + getConstructions(constructionMapTriple.getZeroMap().get(rat)), + getConstructions(constructionMapTriple.getPlusMap().get(rat)), + getConstructions(constructionMapTriple.getMinusMap().get(rat))); LensProjectionContext accountContext = context.findProjectionContext(rat); if (accountContext != null) { // This can be null in a exotic case if we delete already deleted account accountContext.setConstructionDeltaSetTriple(accountDeltaSetTriple); - if (isForceRecon(zeroConstructionMap.get(rat)) || isForceRecon(plusConstructionMap.get(rat)) || isForceRecon(minusConstructionMap.get(rat))) { + if (isForceRecon(constructionMapTriple.getZeroMap().get(rat)) || isForceRecon(constructionMapTriple.getPlusMap().get(rat)) || isForceRecon(constructionMapTriple.getMinusMap().get(rat))) { accountContext.setDoReconciliation(true); } } @@ -708,39 +704,72 @@ private void evaluateConstructions(LensContext context, } } - private void collectToConstructionMap(LensContext context, + private void collectToConstructionMaps(LensContext context, + DeltaSetTriple> evaluatedAssignmentTriple, + DeltaMapTriple constructionMapTriple, + OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { + + collectToConstructionMapFromEvaluatedAssignments(context, evaluatedAssignmentTriple.getZeroSet(), constructionMapTriple, PlusMinusZero.ZERO, result); + collectToConstructionMapFromEvaluatedAssignments(context, evaluatedAssignmentTriple.getPlusSet(), constructionMapTriple, PlusMinusZero.PLUS, result); + collectToConstructionMapFromEvaluatedAssignments(context, evaluatedAssignmentTriple.getMinusSet(), constructionMapTriple, PlusMinusZero.MINUS, result); + } + + private void collectToConstructionMapFromEvaluatedAssignments(LensContext context, Collection> evaluatedAssignments, - Map constructionMap, + DeltaMapTriple constructionMapTriple, PlusMinusZero mode, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { for (EvaluatedAssignment evaluatedAssignment: evaluatedAssignments) { if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Collecting evaluated assignment:\n{}", evaluatedAssignment.debugDump()); + LOGGER.trace("Collecting constructions from evaluated assignment:\n{}", evaluatedAssignment.debugDump()); } - for (Construction construction : evaluatedAssignment.getConstructions()) { - String resourceOid = construction.getResource(result).getOid(); - String intent = construction.getIntent(); - ShadowKindType kind = construction.getKind(); - ResourceType resource = LensUtil.getResource(context, resourceOid, provisioningService, result); - intent = LensUtil.refineProjectionIntent(kind, intent, resource, prismContext); - ResourceShadowDiscriminator rat = new ResourceShadowDiscriminator(resourceOid, kind, intent); - ConstructionPack constructionPack = null; - if (constructionMap.containsKey(rat)) { - constructionPack = constructionMap.get(rat); - } else { - constructionPack = new ConstructionPack(); - constructionMap.put(rat, constructionPack); - } - constructionPack.add(new PrismPropertyValue(construction)); - if (evaluatedAssignment.isValid()) { - constructionPack.setHasValidAssignment(true); - } - if (evaluatedAssignment.isForceRecon()) { - constructionPack.setForceRecon(true); - } - } - } + DeltaSetTriple> constructionTriple = evaluatedAssignment.getConstructions(); + collectToConstructionMapFromEvaluatedConstructions(context, evaluatedAssignment, constructionTriple.getZeroSet(), constructionMapTriple, mode, PlusMinusZero.ZERO, result); + collectToConstructionMapFromEvaluatedConstructions(context, evaluatedAssignment, constructionTriple.getPlusSet(), constructionMapTriple, mode, PlusMinusZero.PLUS, result); + collectToConstructionMapFromEvaluatedConstructions(context, evaluatedAssignment, constructionTriple.getZeroSet(), constructionMapTriple, mode, PlusMinusZero.ZERO, result); + } } + private void collectToConstructionMapFromEvaluatedConstructions(LensContext context, + EvaluatedAssignment evaluatedAssignment, + Collection> evaluatedConstructions, + DeltaMapTriple constructionMapTriple, + PlusMinusZero mode1, PlusMinusZero mode2, + OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException { + + for (Construction construction : evaluatedConstructions) { + + PlusMinusZero mode = PlusMinusZero.compute(mode1, mode2); + Map constructionMap = constructionMapTriple.getMap(mode); + if (constructionMap == null) { + continue; + } + + String resourceOid = construction.getResource(result).getOid(); + String intent = construction.getIntent(); + ShadowKindType kind = construction.getKind(); + ResourceType resource = LensUtil.getResource(context, resourceOid, provisioningService, result); + intent = LensUtil.refineProjectionIntent(kind, intent, resource, prismContext); + ResourceShadowDiscriminator rat = new ResourceShadowDiscriminator(resourceOid, kind, intent); + ConstructionPack constructionPack = null; + if (constructionMap.containsKey(rat)) { + constructionPack = constructionMap.get(rat); + } else { + constructionPack = new ConstructionPack(); + constructionMap.put(rat, constructionPack); + } + constructionPack.add(new PrismPropertyValue(construction)); + if (evaluatedAssignment.isValid()) { + constructionPack.setHasValidAssignment(true); + } + if (evaluatedAssignment.isForceRecon()) { + constructionPack.setForceRecon(true); + } + } + } + + + + private Collection> mergeAssignments( Collection> currentAssignments, Collection> changedAssignments) { @@ -1102,8 +1131,8 @@ private void checkExclusion(LensContext context, Evalua // Same thing, this cannot exclude itself return; } - for(Construction constructionA: assignmentA.getConstructions()) { - for(Construction constructionB: assignmentB.getConstructions()) { + for(Construction constructionA: assignmentA.getConstructions().getNonNegativeValues()) { + for(Construction constructionB: assignmentB.getConstructions().getNonNegativeValues()) { checkExclusion(constructionA, assignmentA, constructionB, assignmentB); } } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentEvaluator.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentEvaluator.java index 86b158f54bd..248ebff3d3f 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentEvaluator.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentEvaluator.java @@ -123,7 +123,7 @@ public void testDirect() throws Exception { assertEquals(1,evaluatedAssignment.getConstructions().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); - Construction construction = evaluatedAssignment.getConstructions().iterator().next(); + Construction construction = evaluatedAssignment.getConstructions().getZeroSet().iterator().next(); display("Evaluated construction", construction); assertNotNull("No object class definition in construction", construction.getRefinedObjectClassDefinition()); } @@ -168,7 +168,7 @@ public void testDirectExpression() throws Exception { assertEquals(1,evaluatedAssignment.getConstructions().size()); PrismAsserts.assertParentConsistency(userTypeJack.asPrismObject()); - Construction construction = evaluatedAssignment.getConstructions().iterator().next(); + Construction construction = evaluatedAssignment.getConstructions().getZeroSet().iterator().next(); assertNotNull("No object class definition in construction", construction.getRefinedObjectClassDefinition()); } @@ -220,7 +220,7 @@ public void testDirectExpressionReplaceDescription() throws Exception { assertEquals(1,evaluatedAssignment.getConstructions().size()); PrismAsserts.assertParentConsistency(user); - Construction construction = evaluatedAssignment.getConstructions().iterator().next(); + Construction construction = evaluatedAssignment.getConstructions().getZeroSet().iterator().next(); assertNotNull("No object class definition in construction", construction.getRefinedObjectClassDefinition()); assertEquals(1,construction.getAttributeMappings().size()); Mapping> attributeMapping = (Mapping>) construction.getAttributeMappings().iterator().next(); @@ -280,7 +280,7 @@ public void testDirectExpressionReplaceDescriptionFromNull() throws Exception { assertEquals(1,evaluatedAssignment.getConstructions().size()); PrismAsserts.assertParentConsistency(user); - Construction construction = evaluatedAssignment.getConstructions().iterator().next(); + Construction construction = evaluatedAssignment.getConstructions().getZeroSet().iterator().next(); assertNotNull("No object class definition in construction", construction.getRefinedObjectClassDefinition()); assertEquals(1,construction.getAttributeMappings().size()); Mapping> attributeMapping = (Mapping>) construction.getAttributeMappings().iterator().next(); From a6c023945dbea34db69a8ff17c9a61b7184c42cc Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 30 Jul 2014 15:52:47 +0200 Subject: [PATCH 40/51] Fixing ItemDeltaItem --- .../midpoint/prism/delta/ContainerDelta.java | 3 +- .../midpoint/prism/delta/ItemDelta.java | 4 ++ .../common/expression/ItemDeltaItem.java | 2 +- .../common/expression/ObjectDeltaObject.java | 49 ++++++++++++++++--- .../model/common/mapping/Mapping.java | 3 ++ 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ContainerDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ContainerDelta.java index 7473ea8172b..2112ec63c55 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ContainerDelta.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ContainerDelta.java @@ -149,7 +149,8 @@ protected boolean isApplicableToType(Item item) { return item instanceof PrismContainer; } - public ItemDelta findItemDelta(ItemPath path) { + @Override + public ItemDelta getSubDelta(ItemPath path) { if (path.isEmpty()) { return this; } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java index 687fd94d5cd..8b7200d26d2 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ItemDelta.java @@ -1002,6 +1002,10 @@ public void applyToMatchingPath(Item item) throws SchemaException { cleanupAllTheWayUp(item); } + public ItemDelta getSubDelta(ItemPath path) { + return this; + } + public boolean isApplicableTo(Item item) { if (item == null) { return false; diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java index 4fc39b69822..48d2350e476 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java @@ -200,7 +200,7 @@ public ItemDeltaItem findIdi(ItemPath path) { ItemDelta subDelta= null; if (delta != null) { if (delta instanceof ContainerDelta) { - subDelta = (ItemDelta) ((ContainerDelta)delta).findItemDelta(path); + subDelta = (ItemDelta) ((ContainerDelta)delta).getSubDelta(path); } else { CompareResult compareComplex = delta.getPath().compareComplex(newResolvePath); if (compareComplex == CompareResult.EQUIVALENT || compareComplex == CompareResult.SUBPATH) { diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ObjectDeltaObject.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ObjectDeltaObject.java index 4775c9f31b1..f805f484efd 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ObjectDeltaObject.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ObjectDeltaObject.java @@ -15,6 +15,9 @@ */ package com.evolveum.midpoint.model.common.expression; +import java.util.ArrayList; +import java.util.Collection; + import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.PartiallyResolvedValue; @@ -26,6 +29,7 @@ import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.delta.PartiallyResolvedDelta; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.path.ItemPath.CompareResult; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.exception.SchemaException; @@ -117,19 +121,48 @@ public ItemDeltaItem findIdi(ItemPath path) { } } } - ItemDelta itemDelta= null; + ItemDelta itemDelta = null; + Collection> subSubItemDeltas = null; if (delta != null) { - PartiallyResolvedDelta partialDelta = delta.findPartial(path); - if (partialDelta != null) { - itemDelta = partialDelta.getDelta(); - if (subResidualPath == null) { - subResidualPath = partialDelta.getResidualPath(); - } + if (delta.getChangeType() == ChangeType.ADD) { + PrismObject objectToAdd = delta.getObjectToAdd(); + PartiallyResolvedValue partialValue = objectToAdd.findPartial(path); + if (partialValue != null && partialValue.getItem() != null) { + Item item = partialValue.getItem(); + itemDelta = item.createDelta(); + itemDelta.addValuesToAdd(item.getClonedValues()); + } else { + // No item for this path, itemDelta will stay empty. + } + } else if (delta.getChangeType() == ChangeType.DELETE) { + // TODO + throw new UnsupportedOperationException("delete"); + } else if (delta.getChangeType() == ChangeType.MODIFY) { + for (ItemDelta modification: delta.getModifications()) { + CompareResult compareComplex = modification.getPath().compareComplex(path); + if (compareComplex == CompareResult.EQUIVALENT) { + if (itemDelta != null) { + throw new IllegalStateException("Conflicting modification in delta "+delta+": "+itemDelta+" and "+modification); + } + itemDelta = (ItemDelta) modification; + } else if (compareComplex == CompareResult.SUPERPATH) { + if (subSubItemDeltas == null) { + subSubItemDeltas = new ArrayList<>(); + } + ((Collection)subSubItemDeltas).add(modification); + } else if (compareComplex == CompareResult.SUBPATH) { + if (itemDelta != null) { + throw new IllegalStateException("Conflicting modification in delta "+delta+": "+itemDelta+" and "+modification); + } + itemDelta = (ItemDelta) modification.getSubDelta(path); + } + } } } ItemDeltaItem subIdi = new ItemDeltaItem(subItemOld, itemDelta, subItemNew); - subIdi.setResidualPath(subResidualPath); + subIdi.setSubItemDeltas(subSubItemDeltas); subIdi.setResolvePath(path); + subIdi.setResidualPath(subResidualPath); return subIdi; } diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java index 52380fbbf91..0920590009c 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java @@ -831,6 +831,7 @@ private Source parseSource(MappingSourceDeclarationTyp ItemDelta delta = null; Item itemNew = null; ItemPath residualPath = null; + Collection> subItemDeltas = null; if (sourceObject != null) { if (sourceObject instanceof ItemDeltaItem) { itemOld = ((ItemDeltaItem)sourceObject).getItemOld(); @@ -838,6 +839,7 @@ private Source parseSource(MappingSourceDeclarationTyp itemNew = ((ItemDeltaItem)sourceObject).getItemNew(); residualPath = ((ItemDeltaItem)sourceObject).getResidualPath(); resolvePath = ((ItemDeltaItem)sourceObject).getResolvePath(); + subItemDeltas = ((ItemDeltaItem)sourceObject).getSubItemDeltas(); } else if (sourceObject instanceof Item) { itemOld = (Item) sourceObject; itemNew = (Item) sourceObject; @@ -848,6 +850,7 @@ private Source parseSource(MappingSourceDeclarationTyp Source source = new Source(itemOld, delta, itemNew, name); source.setResidualPath(residualPath); source.setResolvePath(resolvePath); + source.setSubItemDeltas(subItemDeltas); return source; } From bcd0f0acff28ec40d8dd3a5bf7c36622808865da Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Wed, 30 Jul 2014 16:23:42 +0200 Subject: [PATCH 41/51] Fixing the refactor. --- .../midpoint/model/impl/lens/projector/AssignmentProcessor.java | 2 +- .../midpoint/model/impl/lens/TestAssignmentProcessor.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java index ae713857148..8eaf23a22aa 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/AssignmentProcessor.java @@ -725,7 +725,7 @@ private void collectToConstructionMapFromEvaluatedAssignme DeltaSetTriple> constructionTriple = evaluatedAssignment.getConstructions(); collectToConstructionMapFromEvaluatedConstructions(context, evaluatedAssignment, constructionTriple.getZeroSet(), constructionMapTriple, mode, PlusMinusZero.ZERO, result); collectToConstructionMapFromEvaluatedConstructions(context, evaluatedAssignment, constructionTriple.getPlusSet(), constructionMapTriple, mode, PlusMinusZero.PLUS, result); - collectToConstructionMapFromEvaluatedConstructions(context, evaluatedAssignment, constructionTriple.getZeroSet(), constructionMapTriple, mode, PlusMinusZero.ZERO, result); + collectToConstructionMapFromEvaluatedConstructions(context, evaluatedAssignment, constructionTriple.getMinusSet(), constructionMapTriple, mode, PlusMinusZero.MINUS, result); } } diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor.java index 4058376d98f..1cc6c0b3490 100644 --- a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor.java +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/lens/TestAssignmentProcessor.java @@ -166,6 +166,7 @@ public void test002ModifyUser() throws Exception { PrismValueDeltaSetTriple> accountConstructionDeltaSetTriple = accContext.getConstructionDeltaSetTriple(); + display("accountConstructionDeltaSetTriple", accountConstructionDeltaSetTriple); PrismAsserts.assertTripleNoMinus(accountConstructionDeltaSetTriple); PrismAsserts.assertTripleNoPlus(accountConstructionDeltaSetTriple); From cccea5a5cfb8b082810f81167081aa2b8261d3a3 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Thu, 31 Jul 2014 09:42:22 +0200 Subject: [PATCH 42/51] More work on role conditions, still work in progress. --- .../midpoint/prism/delta/DeltaSetTriple.java | 16 +++ .../prism/parser/util/XNodeProcessorUtil.java | 2 +- .../evolveum/midpoint/prism/xnode/XNode.java | 4 +- .../xml/ns/public/common/common-3.xsd | 25 +++-- .../evolveum/midpoint/util/Transformer.java | 4 +- .../model/impl/lens/AssignmentEvaluator.java | 97 ++++++++++++++++--- .../projector/MappingEvaluationHelper.java | 8 +- .../midpoint/model/intest/TestRbac.java | 84 ++++++++++++++++ .../resources/rbac/role-honorable-wannabe.xml | 44 +++++++++ .../src/test/resources/rbac/role-wannabe.xml | 81 ++++++++++++++++ 10 files changed, 332 insertions(+), 33 deletions(-) create mode 100644 model/model-intest/src/test/resources/rbac/role-honorable-wannabe.xml create mode 100644 model/model-intest/src/test/resources/rbac/role-wannabe.xml diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/DeltaSetTriple.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/DeltaSetTriple.java index 6a5c2828d44..c96c6868b32 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/DeltaSetTriple.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/DeltaSetTriple.java @@ -23,6 +23,7 @@ import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.Transformer; import java.io.Serializable; import java.util.ArrayList; @@ -324,6 +325,21 @@ private void acceptSet(SimpleVisitor visitor, Collection set) { visitor.visit(element); } } + + public void transform(DeltaSetTriple transformTarget, Transformer transformer) { + for (T orig: getZeroSet()) { + X transformed = transformer.transform(orig); + transformTarget.addToZeroSet(transformed); + } + for (T orig: getPlusSet()) { + X transformed = transformer.transform(orig); + transformTarget.addToPlusSet(transformed); + } + for (T orig: getMinusSet()) { + X transformed = transformer.transform(orig); + transformTarget.addToMinusSet(transformed); + } + } @Override public String toString() { diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/parser/util/XNodeProcessorUtil.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/parser/util/XNodeProcessorUtil.java index 171dd81dade..943d643bcf4 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/parser/util/XNodeProcessorUtil.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/parser/util/XNodeProcessorUtil.java @@ -55,7 +55,7 @@ public static void parseProtectedType(ProtectedDataType protectedType, Ma // xmlCipherData.getSingleSubEntry(ProtectedDataType.F_XML_ENC_CIPHER_VALUE.getLocalPart()); - MapXNode xConvertedEncryptedData = (MapXNode) xLegacyEncryptedData.cloneTransformKeys(new Transformer() { + MapXNode xConvertedEncryptedData = (MapXNode) xLegacyEncryptedData.cloneTransformKeys(new Transformer() { @Override public QName transform(QName in) { String elementName = StringUtils.uncapitalize(in.getLocalPart()); diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/xnode/XNode.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/xnode/XNode.java index d0cfa77bd25..31d608d57c4 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/xnode/XNode.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/xnode/XNode.java @@ -141,11 +141,11 @@ public XNode clone() { return cloneTransformKeys(null); } - public XNode cloneTransformKeys(Transformer keyTransformer) { + public XNode cloneTransformKeys(Transformer keyTransformer) { return cloneTransformKeys(keyTransformer, this); } - private X cloneTransformKeys(Transformer keyTransformer, X xnode) { + private X cloneTransformKeys(Transformer keyTransformer, X xnode) { if (xnode instanceof PrimitiveXNode) { return xnode; } else if (xnode instanceof MapXNode) { diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd index 7fb9fd2108b..9501f88dd18 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd @@ -2592,6 +2592,15 @@ + + + + + The assignment is applied only if the condition is evaluated to true. + If condition is not present, it is assumed to be true. + + + @@ -6105,6 +6114,14 @@ + + + + The role is applied only if the condition is evaluated to true. + If condition is not present, it is assumed to be true. + + + @@ -6587,14 +6604,6 @@ - - - - The account is implied only if the condition is evaluated to true. - If condition is not present, it is assumed to be true. - - - diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/Transformer.java b/infra/util/src/main/java/com/evolveum/midpoint/util/Transformer.java index 91a36a87500..e5ddc8d174c 100644 --- a/infra/util/src/main/java/com/evolveum/midpoint/util/Transformer.java +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/Transformer.java @@ -19,8 +19,8 @@ * @author semancik * */ -public interface Transformer { +public interface Transformer { - T transform(T in); + X transform(T in); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java index 2241e8ada69..904194c52df 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java @@ -28,23 +28,33 @@ import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject; import com.evolveum.midpoint.model.common.mapping.Mapping; import com.evolveum.midpoint.model.common.mapping.MappingFactory; +import com.evolveum.midpoint.model.impl.lens.projector.MappingEvaluationHelper; import com.evolveum.midpoint.prism.Containerable; 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.PrismContainerable; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.OriginType; +import com.evolveum.midpoint.prism.PrismPropertyDefinition; +import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.delta.DeltaSetTriple; 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.repo.api.RepositoryService; +import com.evolveum.midpoint.schema.constants.ExpressionConstants; +import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ObjectResolver; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.security.api.Authorization; import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.DOMUtil; +import com.evolveum.midpoint.util.Transformer; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; @@ -72,6 +82,8 @@ */ public class AssignmentEvaluator { + private static final QName CONDITION_OUTPUT_NAME = new QName(SchemaConstants.NS_C, "condition"); + private static final Trace LOGGER = TraceManager.getTrace(AssignmentEvaluator.class); private RepositoryService repository; @@ -85,6 +97,7 @@ public class AssignmentEvaluator { XMLGregorianCalendar now; private boolean evaluateConstructions = true; private PrismObject systemConfiguration; + private MappingEvaluationHelper mappingEvaluationHelper; public RepositoryService getRepository() { return repository; @@ -174,6 +187,14 @@ public void setSystemConfiguration(PrismObject systemCo this.systemConfiguration = systemConfiguration; } + public MappingEvaluationHelper getMappingEvaluationHelper() { + return mappingEvaluationHelper; + } + + public void setMappingEvaluationHelper(MappingEvaluationHelper mappingEvaluationHelper) { + this.mappingEvaluationHelper = mappingEvaluationHelper; + } + public EvaluatedAssignment evaluate(ItemDeltaItem> assignmentIdi, boolean evaluateOld, ObjectType source, String sourceDescription, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { @@ -371,30 +392,40 @@ private void evaluateTarget(EvaluatedAssignment assignment, AssignmentPathSeg } } - private void evaluateAbstractRole(EvaluatedAssignment assignment, AssignmentPathSegment assignmentPathSegment, - boolean evaluateOld, AbstractRoleType role, ObjectType source, String sourceDescription, + private boolean evaluateAbstractRole(EvaluatedAssignment assignment, AssignmentPathSegment assignmentPathSegment, + boolean evaluateOld, AbstractRoleType roleType, ObjectType source, String sourceDescription, AssignmentPath assignmentPath, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { assertSource(source, assignment); + MappingType conditionType = roleType.getCondition(); + if (conditionType != null) { + DeltaSetTriple conditionTriple = evaluateMappingAsCondition(conditionType, source, task, result); + if (conditionTriple != null) { + // TODO + + + } + } + int evaluationOrder = assignmentPath.getEvaluationOrder(); ObjectType orderOneObject; if (evaluationOrder == 1) { - orderOneObject = role; + orderOneObject = roleType; } else { AssignmentPathSegment last = assignmentPath.last(); if (last != null && last.getOrderOneObject() != null) { orderOneObject = last.getOrderOneObject(); } else { - orderOneObject = role; + orderOneObject = roleType; } } - for (AssignmentType roleInducement : role.getInducement()) { + for (AssignmentType roleInducement : roleType.getInducement()) { ItemDeltaItem> roleInducementIdi = new ItemDeltaItem<>(); roleInducementIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(roleInducement)); roleInducementIdi.recompute(); AssignmentPathSegment roleAssignmentPathSegment = new AssignmentPathSegment(roleInducementIdi, null); - roleAssignmentPathSegment.setSource(role); - String subSourceDescription = role+" in "+sourceDescription; + roleAssignmentPathSegment.setSource(roleType); + String subSourceDescription = roleType+" in "+sourceDescription; Integer inducementOrder = roleInducement.getOrder(); if (inducementOrder == null) { inducementOrder = 1; @@ -402,12 +433,12 @@ private void evaluateAbstractRole(EvaluatedAssignment assignment, AssignmentP if (inducementOrder == evaluationOrder) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("E{}: evaluate inducement({}) {} in {}", - new Object[]{evaluationOrder, inducementOrder, dumpAssignment(roleInducement), role}); + new Object[]{evaluationOrder, inducementOrder, dumpAssignment(roleInducement), roleType}); } roleAssignmentPathSegment.setEvaluateConstructions(true); roleAssignmentPathSegment.setEvaluationOrder(evaluationOrder); roleAssignmentPathSegment.setOrderOneObject(orderOneObject); - evaluateAssignment(assignment, roleAssignmentPathSegment, evaluateOld, role, subSourceDescription, assignmentPath, task, result); + evaluateAssignment(assignment, roleAssignmentPathSegment, evaluateOld, roleType, subSourceDescription, assignmentPath, task, result); // } else if (inducementOrder < assignmentPath.getEvaluationOrder()) { // LOGGER.trace("Follow({}) inducement({}) in role {}", // new Object[]{evaluationOrder, inducementOrder, source}); @@ -417,30 +448,32 @@ private void evaluateAbstractRole(EvaluatedAssignment assignment, AssignmentP } else { if (LOGGER.isTraceEnabled()) { LOGGER.trace("E{}: NOT evaluate inducement({}) {} in {}", - new Object[]{evaluationOrder, inducementOrder, dumpAssignment(roleInducement), role}); + new Object[]{evaluationOrder, inducementOrder, dumpAssignment(roleInducement), roleType}); } } } - for (AssignmentType roleAssignment : role.getAssignment()) { + for (AssignmentType roleAssignment : roleType.getAssignment()) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("E{}: follow assignment {} in {}", - new Object[]{evaluationOrder, dumpAssignment(roleAssignment), role}); + new Object[]{evaluationOrder, dumpAssignment(roleAssignment), roleType}); } ItemDeltaItem> roleAssignmentIdi = new ItemDeltaItem<>(); roleAssignmentIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(roleAssignment)); roleAssignmentIdi.recompute(); AssignmentPathSegment roleAssignmentPathSegment = new AssignmentPathSegment(roleAssignmentIdi, null); - roleAssignmentPathSegment.setSource(role); - String subSourceDescription = role+" in "+sourceDescription; + roleAssignmentPathSegment.setSource(roleType); + String subSourceDescription = roleType+" in "+sourceDescription; roleAssignmentPathSegment.setEvaluateConstructions(false); roleAssignmentPathSegment.setEvaluationOrder(evaluationOrder+1); roleAssignmentPathSegment.setOrderOneObject(orderOneObject); - evaluateAssignment(assignment, roleAssignmentPathSegment, evaluateOld, role, subSourceDescription, assignmentPath, task, result); + evaluateAssignment(assignment, roleAssignmentPathSegment, evaluateOld, roleType, subSourceDescription, assignmentPath, task, result); } - for(AuthorizationType authorizationType: role.getAuthorization()) { + for(AuthorizationType authorizationType: roleType.getAuthorization()) { Authorization authorization = createAuthorization(authorizationType); assignment.addAuthorization(authorization); } + + return true; } public static String dumpAssignment(AssignmentType assignmentType) { @@ -496,5 +529,37 @@ private void checkSchema(AssignmentType assignmentType, String sourceDescription } } } + + public DeltaSetTriple evaluateMappingAsCondition(MappingType conditionType, ObjectType source, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { + Mapping> mapping = mappingFactory.createMapping(conditionType, + "condition in " + source); + + mapping.addVariableDefinition(ExpressionConstants.VAR_USER, focusOdo); + mapping.addVariableDefinition(ExpressionConstants.VAR_FOCUS, focusOdo); + mapping.addVariableDefinition(ExpressionConstants.VAR_SOURCE, source); + mapping.setSourceContext(focusOdo); + mapping.setRootNode(focusOdo); + mapping.setOriginType(OriginType.ASSIGNMENTS); + mapping.setOriginObject(source); + + // TODO: assignment path variables? + + ItemDefinition outputDefinition = new PrismPropertyDefinition(CONDITION_OUTPUT_NAME, DOMUtil.XSD_BOOLEAN, prismContext); + mapping.setDefaultTargetDefinition(outputDefinition); + + LensUtil.evaluateMapping(mapping, lensContext, task, result); + + PrismValueDeltaSetTriple> mappingOutputTriple = mapping.getOutputTriple(); + DeltaSetTriple outputTriple = new DeltaSetTriple<>(); + Transformer, Boolean> transformer = new Transformer, Boolean>() { + @Override + public Boolean transform(PrismPropertyValue in) { + return in.getValue(); + } + }; + mappingOutputTriple.transform(outputTriple, transformer); + return outputTriple; + } + } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/MappingEvaluationHelper.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/MappingEvaluationHelper.java index e571d27c37a..4c8f2725450 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/MappingEvaluationHelper.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/MappingEvaluationHelper.java @@ -54,9 +54,11 @@ import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; import com.evolveum.midpoint.prism.delta.PropertyDelta; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.schema.constants.ExpressionConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.Handler; +import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; @@ -82,7 +84,7 @@ public class MappingEvaluationHelper { private PrismContext prismContext; @Autowired(required = true) - private MappingFactory valueConstructionFactory; + private MappingFactory mappingFactory; /** * strongMappingWasUsed: Returns true here if the value was (at least partly) determined by a strong mapping. @@ -114,7 +116,7 @@ public void ev for (MappingType mappingType: mappingTypes) { - Mapping mapping = valueConstructionFactory.createMapping(mappingType, mappingDesc); + Mapping mapping = mappingFactory.createMapping(mappingType, mappingDesc); if (!mapping.isApplicableToChannel(params.getContext().getChannel())) { continue; @@ -381,7 +383,5 @@ public void setStrongMappingWasUsed(boolean strongMappingWasUsed) { } - - } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java index d2951c4c96e..cdfea21c353 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java @@ -91,6 +91,12 @@ public class TestRbac extends AbstractInitializedModelIntegrationTest { protected static final File ROLE_CLERIC_FILE = new File(TEST_DIR, "role-cleric.xml"); protected static final String ROLE_CLERIC_OID = "12345678-d34d-b33f-f00d-555555557702"; + + protected static final File ROLE_WANNABE_FILE = new File(TEST_DIR, "role-wannabe.xml"); + protected static final String ROLE_WANNABE_OID = "12345678-d34d-b33f-f00d-555555557703"; + + protected static final File ROLE_HONORABLE_WANNABE_FILE = new File(TEST_DIR, "role-honorable-wannabe.xml"); + protected static final String ROLE_HONORABLE_WANNABE_OID = "12345678-d34d-b33f-f00d-555555557704"; private final String EXISTING_GOSSIP = "Black spot!"; @@ -109,6 +115,8 @@ public void initSystem(Task initTask, OperationResult initResult) repoAddObjectFromFile(ROLE_INDIAN_OCEAN_PIRATE_FILE, RoleType.class, initResult); repoAddObjectFromFile(ROLE_HONORABILITY_FILE, RoleType.class, initResult); repoAddObjectFromFile(ROLE_CLERIC_FILE, RoleType.class, initResult); + repoAddObjectFromFile(ROLE_WANNABE_FILE, RoleType.class, initResult); + repoAddObjectFromFile(ROLE_HONORABLE_WANNABE_FILE, RoleType.class, initResult); } @Test @@ -1036,6 +1044,82 @@ public void test539JackUnAssignRoleCleric() throws Exception { assertNoDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME); } + /** + * Wannabe role is conditional. All conditions should be false now. So no provisioning should happen. + */ + @Test + public void test540JackAssignRoleWannabe() throws Exception { + final String TEST_NAME = "test540JackAssignRoleWannabe"; + TestUtil.displayTestTile(this, TEST_NAME); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + assignRole(USER_JACK_OID, ROLE_WANNABE_OID); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertAssignedRole(USER_JACK_OID, ROLE_WANNABE_OID, task, result); + assertNoDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME); + } + + /** + * Modify employeeType. This triggers a condition in Wannabe role. + */ + @Test + public void test541JackModifyEmployeeTypeWannabe() throws Exception { + final String TEST_NAME = "test541JackModifyEmployeeTypeWannabe"; + TestUtil.displayTestTile(this, TEST_NAME); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modifyUserReplace(USER_JACK_OID, UserType.F_EMPLOYEE_TYPE, task, result, "wannabe"); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertAssignedRole(USER_JACK_OID, ROLE_WANNABE_OID, task, result); + assertDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME, ACCOUNT_JACK_DUMMY_FULLNAME, true); + assertDefaultDummyAccountAttribute(ACCOUNT_JACK_DUMMY_USERNAME, "title", "Wannabe Cpt. Where's the rum?"); + } + + /** + * The account should be gone - regardless of the condition state. + */ + @Test + public void test549JackUnassignRoleWannabe() throws Exception { + final String TEST_NAME = "test549JackUnassignRoleWannabe"; + TestUtil.displayTestTile(this, TEST_NAME); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + unassignRole(USER_JACK_OID, ROLE_WANNABE_OID); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertNotAssignedRole(USER_JACK_OID, ROLE_WANNABE_OID, task, result); + assertNoDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME); + } + @Test public void test600JackAssignRoleJudge() throws Exception { final String TEST_NAME = "test600JackAssignRoleJudge"; diff --git a/model/model-intest/src/test/resources/rbac/role-honorable-wannabe.xml b/model/model-intest/src/test/resources/rbac/role-honorable-wannabe.xml new file mode 100644 index 00000000000..7e728540f86 --- /dev/null +++ b/model/model-intest/src/test/resources/rbac/role-honorable-wannabe.xml @@ -0,0 +1,44 @@ + + + Honorable Wannabe + Included from Wannabe role + + + + account + + ri:quote + + + $user/name + + + + + + + + + diff --git a/model/model-intest/src/test/resources/rbac/role-wannabe.xml b/model/model-intest/src/test/resources/rbac/role-wannabe.xml new file mode 100644 index 00000000000..e2e72ad8484 --- /dev/null +++ b/model/model-intest/src/test/resources/rbac/role-wannabe.xml @@ -0,0 +1,81 @@ + + + Wannabe + A role full of conditions + + + + account + + ri:title + + + $user/description + + + $user/honorificPrefix + + + + + + + + + + $user/honorificPrefix + + + + + + + + + + + + $user/honorificSuffix + + + + + + + + + $user/employeeType + + + + + + From 641bed582881e16ba962cda6725840b451338835 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Thu, 31 Jul 2014 10:47:31 +0200 Subject: [PATCH 43/51] Fixing itemdeltaitem delete bug. Some cleanup. --- .../com/evolveum/midpoint/prism/Item.java | 2 +- ...dValue.java => PartiallyResolvedItem.java} | 10 ++++----- .../midpoint/prism/PrismContainer.java | 4 ++-- .../midpoint/prism/PrismContainerValue.java | 2 +- .../midpoint/prism/PrismProperty.java | 18 +++++++++------- .../midpoint/prism/PrismPropertyValue.java | 12 ++--------- .../midpoint/prism/PrismReference.java | 4 ++-- .../midpoint/prism/PrismReferenceValue.java | 6 +++--- .../evolveum/midpoint/prism/PrismValue.java | 2 +- .../midpoint/prism/delta/ObjectDelta.java | 4 ++-- .../common/expression/ItemDeltaItem.java | 6 +++--- .../common/expression/ObjectDeltaObject.java | 21 +++++++++++++------ 12 files changed, 48 insertions(+), 43 deletions(-) rename infra/prism/src/main/java/com/evolveum/midpoint/prism/{PartiallyResolvedValue.java => PartiallyResolvedItem.java} (85%) diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/Item.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/Item.java index 95a4b4e67e6..2c0180a1d4a 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/Item.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/Item.java @@ -445,7 +445,7 @@ public void merge(Item otherItem) throws SchemaException { public abstract Object find(ItemPath path); - public abstract PartiallyResolvedValue findPartial(ItemPath path); + public abstract PartiallyResolvedItem findPartial(ItemPath path); public Collection diff(Item other) { return diff(other, true, false); diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PartiallyResolvedValue.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PartiallyResolvedItem.java similarity index 85% rename from infra/prism/src/main/java/com/evolveum/midpoint/prism/PartiallyResolvedValue.java rename to infra/prism/src/main/java/com/evolveum/midpoint/prism/PartiallyResolvedItem.java index 642320eadab..c8d426fbaf3 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PartiallyResolvedValue.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PartiallyResolvedItem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2014 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,12 +21,12 @@ * @author semancik * */ -public class PartiallyResolvedValue { +public class PartiallyResolvedItem { private Item item; private ItemPath residualPath; - public PartiallyResolvedValue(Item item, ItemPath residualPath) { + public PartiallyResolvedItem(Item item, ItemPath residualPath) { super(); this.item = item; this.residualPath = residualPath; @@ -65,7 +65,7 @@ public boolean equals(Object obj) { return false; if (getClass() != obj.getClass()) return false; - PartiallyResolvedValue other = (PartiallyResolvedValue) obj; + PartiallyResolvedItem other = (PartiallyResolvedItem) obj; if (item == null) { if (other.item != null) return false; @@ -81,7 +81,7 @@ public boolean equals(Object obj) { @Override public String toString() { - return "PartiallyResolvedValue(item=" + item + ", residualPath=" + residualPath + ")"; + return "PartiallyResolvedItem(item=" + item + ", residualPath=" + residualPath + ")"; } } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java index d6fe8a1c7bd..a04f23eaa02 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainer.java @@ -352,9 +352,9 @@ public Object find(ItemPath path) { } @Override - public PartiallyResolvedValue findPartial(ItemPath path) { + public PartiallyResolvedItem findPartial(ItemPath path) { if (path == null || path.isEmpty()) { - return new PartiallyResolvedValue((Item)this, null); + return new PartiallyResolvedItem((Item)this, null); } IdItemPathSegment idSegment = ItemPath.getFirstIdSegment(path); diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java index cecd3071711..6e90e7c0154 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismContainerValue.java @@ -532,7 +532,7 @@ public Object find(ItemPath path) { } @Override - public PartiallyResolvedValue findPartial(ItemPath path) { + public PartiallyResolvedItem findPartial(ItemPath path) { if (path == null || path.isEmpty()) { // Incomplete path return null; diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismProperty.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismProperty.java index 5115b55fb3b..c1de1129170 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismProperty.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismProperty.java @@ -22,6 +22,8 @@ import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.PrettyPrinter; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; @@ -361,15 +363,17 @@ public Object find(ItemPath path) { } @Override - public PartiallyResolvedValue findPartial(ItemPath path) { + public PartiallyResolvedItem findPartial(ItemPath path) { if (path == null || path.isEmpty()) { - return new PartiallyResolvedValue((Item)this, null); + return new PartiallyResolvedItem((Item)this, null); } - if (!isSingleValue()) { - throw new IllegalStateException("Attempt to resolve sub-path '"+path+"' on multi-value property " + getElementName()); - } - PrismPropertyValue value = getValue(); - return value.findPartial(path); + for (PrismPropertyValue pvalue: getValues()) { + T value = pvalue.getValue(); + if (!(value instanceof Structured)) { + throw new IllegalArgumentException("Attempt to resolve sub-path '"+path+"' on non-structured property value "+pvalue); + } + } + return new PartiallyResolvedItem((Item)this, path); } public PropertyDelta diff(PrismProperty other) { diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismPropertyValue.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismPropertyValue.java index b7447603355..39322e49e47 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismPropertyValue.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismPropertyValue.java @@ -209,16 +209,8 @@ public Object find(ItemPath path) { } @Override - public PartiallyResolvedValue findPartial(ItemPath path) { - if (path == null || path.isEmpty()) { - return new PartiallyResolvedValue((Item)getParent(), null); - } - T value = getValue(); - if (value instanceof Structured) { - return new PartiallyResolvedValue((Item)getParent(), path); - } else { - throw new IllegalArgumentException("Attempt to resolve sub-path '"+path+"' on non-structured property value "+value); - } + public PartiallyResolvedItem findPartial(ItemPath path) { + throw new UnsupportedOperationException("Attempt to invoke findPartialItem on a property value"); } void checkValue() { diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReference.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReference.java index d598d31beab..3361507ab54 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReference.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReference.java @@ -175,9 +175,9 @@ public Object find(ItemPath path) { @Override - public PartiallyResolvedValue findPartial(ItemPath path) { + public PartiallyResolvedItem findPartial(ItemPath path) { if (path == null || path.isEmpty()) { - return new PartiallyResolvedValue((Item)this, null); + return new PartiallyResolvedItem((Item)this, null); } if (!isSingleValue()) { throw new IllegalStateException("Attempt to resolve sub-path '"+path+"' on multi-value reference " + getElementName()); diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java index 6c9f5ed9549..f597236c677 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java @@ -190,11 +190,11 @@ public Object find(ItemPath path) { } @Override - public PartiallyResolvedValue findPartial(ItemPath path) { + public PartiallyResolvedItem findPartial(ItemPath path) { if (path == null || path.isEmpty()) { - return new PartiallyResolvedValue((Item)getParent(), null); + return new PartiallyResolvedItem((Item)getParent(), null); } - return new PartiallyResolvedValue((Item)getParent(), path); + return new PartiallyResolvedItem((Item)getParent(), path); } private boolean compareLocalPart(QName a, QName b) { 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 bc1392ab609..2ef4a573f0c 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 @@ -252,7 +252,7 @@ public static Collection resetParentCollection(Collect public abstract Object find(ItemPath path); - public abstract PartiallyResolvedValue findPartial(ItemPath path); + public abstract PartiallyResolvedItem findPartial(ItemPath path); @Override public int hashCode() { diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java index 1b74698191f..ceafd01a723 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/ObjectDelta.java @@ -19,7 +19,7 @@ import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.Objectable; -import com.evolveum.midpoint.prism.PartiallyResolvedValue; +import com.evolveum.midpoint.prism.PartiallyResolvedItem; import com.evolveum.midpoint.prism.PathVisitable; import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismContainerDefinition; @@ -269,7 +269,7 @@ private D findItemDelta(ItemPath propertyP public PartiallyResolvedDelta findPartial(ItemPath propertyPath) { if (changeType == ChangeType.ADD) { - PartiallyResolvedValue partialValue = objectToAdd.findPartial(propertyPath); + PartiallyResolvedItem partialValue = objectToAdd.findPartial(propertyPath); if (partialValue == null || partialValue.getItem() == null) { return null; } diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java index 48d2350e476..f558963f271 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ItemDeltaItem.java @@ -22,7 +22,7 @@ import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; -import com.evolveum.midpoint.prism.PartiallyResolvedValue; +import com.evolveum.midpoint.prism.PartiallyResolvedItem; import com.evolveum.midpoint.prism.PrismContainer; import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.prism.PrismPropertyDefinition; @@ -181,7 +181,7 @@ public ItemDeltaItem findIdi(ItemPath path) { ItemPath subResidualPath = null; ItemPath newResolvePath = resolvePath.subPath(path); if (itemOld != null) { - PartiallyResolvedValue partialItemOld = itemOld.findPartial(path); + PartiallyResolvedItem partialItemOld = itemOld.findPartial(path); if (partialItemOld != null) { subItemOld = partialItemOld.getItem(); subResidualPath = partialItemOld.getResidualPath(); @@ -189,7 +189,7 @@ public ItemDeltaItem findIdi(ItemPath path) { } Item subItemNew = null; if (itemNew != null) { - PartiallyResolvedValue partialItemNew = itemNew.findPartial(path); + PartiallyResolvedItem partialItemNew = itemNew.findPartial(path); if (partialItemNew != null) { subItemNew = partialItemNew.getItem(); if (subResidualPath == null) { diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ObjectDeltaObject.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ObjectDeltaObject.java index f805f484efd..d5b802c90b6 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ObjectDeltaObject.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ObjectDeltaObject.java @@ -20,7 +20,7 @@ import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; -import com.evolveum.midpoint.prism.PartiallyResolvedValue; +import com.evolveum.midpoint.prism.PartiallyResolvedItem; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismValue; @@ -105,7 +105,7 @@ public ItemDeltaItem findIdi(ItemPath path) { Item subItemOld = null; ItemPath subResidualPath = null; if (oldObject != null) { - PartiallyResolvedValue partialOld = oldObject.findPartial(path); + PartiallyResolvedItem partialOld = oldObject.findPartial(path); if (partialOld != null) { subItemOld = partialOld.getItem(); subResidualPath = partialOld.getResidualPath(); @@ -113,7 +113,7 @@ public ItemDeltaItem findIdi(ItemPath path) { } Item subItemNew = null; if (newObject != null) { - PartiallyResolvedValue partialNew = newObject.findPartial(path); + PartiallyResolvedItem partialNew = newObject.findPartial(path); if (partialNew != null) { subItemNew = partialNew.getItem(); if (subResidualPath == null) { @@ -126,7 +126,7 @@ public ItemDeltaItem findIdi(ItemPath path) { if (delta != null) { if (delta.getChangeType() == ChangeType.ADD) { PrismObject objectToAdd = delta.getObjectToAdd(); - PartiallyResolvedValue partialValue = objectToAdd.findPartial(path); + PartiallyResolvedItem partialValue = objectToAdd.findPartial(path); if (partialValue != null && partialValue.getItem() != null) { Item item = partialValue.getItem(); itemDelta = item.createDelta(); @@ -135,8 +135,17 @@ public ItemDeltaItem findIdi(ItemPath path) { // No item for this path, itemDelta will stay empty. } } else if (delta.getChangeType() == ChangeType.DELETE) { - // TODO - throw new UnsupportedOperationException("delete"); + if (subItemOld != null) { + ItemPath subPath = subItemOld.getPath().remainder(path); + PartiallyResolvedItem partialValue = subItemOld.findPartial(subPath); + if (partialValue != null && partialValue.getItem() != null) { + Item item = partialValue.getItem(); + itemDelta = item.createDelta(); + itemDelta.addValuesToDelete(item.getClonedValues()); + } else { + // No item for this path, itemDelta will stay empty. + } + } } else if (delta.getChangeType() == ChangeType.MODIFY) { for (ItemDelta modification: delta.getModifications()) { CompareResult compareComplex = modification.getPath().compareComplex(path); From 1c57aa08daa581313f0a9b3cc01ec25c5eb386ab Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Thu, 31 Jul 2014 13:34:24 +0200 Subject: [PATCH 44/51] Role conditions almost done, assignment conditions almost almost done (untested). --- .../midpoint/prism/polystring/PolyString.java | 4 + .../prism/util/JavaTypeConverter.java | 6 ++ infra/schema/.gitignore | 1 + .../common/expression/ExpressionUtil.java | 38 +++++++++ .../model/common/mapping/Mapping.java | 20 +---- .../model/impl/lens/AssignmentEvaluator.java | 83 ++++++++++++------- .../model/impl/lens/EvaluatedAssignment.java | 8 ++ .../src/test/resources/rbac/role-wannabe.xml | 4 +- 8 files changed, 112 insertions(+), 52 deletions(-) diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/polystring/PolyString.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/polystring/PolyString.java index b941d62ecf5..b5588417127 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/polystring/PolyString.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/polystring/PolyString.java @@ -155,6 +155,10 @@ public PolyString getAt(int index) { public int length() { return orig.length(); } + + public PolyString trim() { + return new PolyString(orig.trim(), norm.trim()); + } @Override public int hashCode() { diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/JavaTypeConverter.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/JavaTypeConverter.java index e7a4b47f607..e47b947df11 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/JavaTypeConverter.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/util/JavaTypeConverter.java @@ -81,9 +81,15 @@ public static T convert(Class expectedType, Object rawValue) { if (expectedType == Boolean.class && rawValue instanceof String) { return (T) (Boolean)Boolean.parseBoolean(((String)rawValue)); } + if (expectedType == Boolean.class && rawValue instanceof PolyString) { + return (T) (Boolean)Boolean.parseBoolean(((PolyString)rawValue).toString()); + } if (expectedType == boolean.class && rawValue instanceof String) { return (T) (Boolean)Boolean.parseBoolean(((String)rawValue)); } + if (expectedType == boolean.class && rawValue instanceof PolyString) { + return (T) (Boolean)Boolean.parseBoolean(((PolyString)rawValue).toString()); + } if (expectedType == String.class && rawValue instanceof Boolean) { return (T) rawValue.toString(); } diff --git a/infra/schema/.gitignore b/infra/schema/.gitignore index 06b36c10961..8f9645e1a48 100644 --- a/infra/schema/.gitignore +++ b/infra/schema/.gitignore @@ -16,3 +16,4 @@ /target /target /target +/target diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionUtil.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionUtil.java index a9da7a8a99f..a2b43b5caed 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionUtil.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/ExpressionUtil.java @@ -54,6 +54,7 @@ import com.evolveum.midpoint.prism.crypto.EncryptionException; import com.evolveum.midpoint.prism.crypto.Protector; import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.prism.delta.PlusMinusZero; import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.path.ItemPathSegment; @@ -552,5 +553,42 @@ public static boolean hasExplicitTarget(List mappingTypes) { private static boolean hasExplicitTarget(MappingType mappingType) { return mappingType.getTarget() != null; } + + public static boolean computeConditionResult(Collection> booleanPropertyValues) { + if (booleanPropertyValues == null || booleanPropertyValues.isEmpty()) { + // No value means false + return false; + } + boolean hasFalse = false; + for (PrismPropertyValue pval: booleanPropertyValues) { + Boolean value = pval.getValue(); + if (Boolean.TRUE.equals(value)) { + return true; + } + if (Boolean.FALSE.equals(value)) { + hasFalse = true; + } + } + if (hasFalse) { + return false; + } + // No value or all values null. Return default. + return true; + } + public static PlusMinusZero computeConditionResultMode(boolean condOld, boolean condNew) { + if (condOld && condNew) { + return PlusMinusZero.ZERO; + } + if (!condOld && !condNew) { + return null; + } + if (condOld && !condNew) { + return PlusMinusZero.MINUS; + } + if (!condOld && condNew) { + return PlusMinusZero.PLUS; + } + throw new IllegalStateException("notreached"); + } } diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java index 0920590009c..b7364d64a40 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/Mapping.java @@ -647,25 +647,7 @@ private boolean computeConditionResult(Collection> b // If condition is not present at all consider it to be true return true; } - if (booleanPropertyValues == null || booleanPropertyValues.isEmpty()) { - // No value means false - return false; - } - boolean hasFalse = false; - for (PrismPropertyValue pval: booleanPropertyValues) { - Boolean value = pval.getValue(); - if (Boolean.TRUE.equals(value)) { - return true; - } - if (Boolean.FALSE.equals(value)) { - hasFalse = true; - } - } - if (hasFalse) { - return false; - } - // No value or all values null. Return default. - return true; + return ExpressionUtil.computeConditionResult(booleanPropertyValues); } public Boolean evaluateTimeConstraintValid(OperationResult result) throws SchemaException, ObjectNotFoundException { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java index 904194c52df..e69f0e3af97 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java @@ -24,6 +24,7 @@ import com.evolveum.midpoint.common.ActivationComputer; import com.evolveum.midpoint.model.api.PolicyViolationException; +import com.evolveum.midpoint.model.common.expression.ExpressionUtil; import com.evolveum.midpoint.model.common.expression.ItemDeltaItem; import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject; import com.evolveum.midpoint.model.common.mapping.Mapping; @@ -44,6 +45,7 @@ import com.evolveum.midpoint.prism.delta.DeltaSetTriple; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.delta.PlusMinusZero; import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.constants.ExpressionConstants; @@ -208,7 +210,7 @@ public EvaluatedAssignment evaluate(ItemDeltaItem evaluate(ItemDeltaItem evalAssignment, AssignmentPathSegment assignmentPathSegment, - boolean evaluateOld, ObjectType source, String sourceDescription, + boolean evaluateOld, PlusMinusZero mode, ObjectType source, String sourceDescription, AssignmentPath assignmentPath, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { assertSource(source, evalAssignment); - LOGGER.trace("Evaluate assignment {} (eval constr: {})", assignmentPath, assignmentPathSegment.isEvaluateConstructions()); + LOGGER.trace("Evaluate assignment {} (eval constr: {}, mode: {})", new Object[]{ + assignmentPath, assignmentPathSegment.isEvaluateConstructions(), mode}); ItemDeltaItem> assignmentIdi = assignmentPathSegment.getAssignmentIdi(); AssignmentType assignmentType = LensUtil.getAssignmentType(assignmentIdi, evaluateOld); @@ -250,13 +253,28 @@ private void evaluateAssignment(EvaluatedAssignment evalAssignment, Assignmen assignmentPath.add(assignmentPathSegment); + MappingType conditionType = assignmentType.getCondition(); + if (conditionType != null) { + PrismValueDeltaSetTriple> conditionTriple = evaluateMappingAsCondition(conditionType, source, task, result); + boolean condOld = ExpressionUtil.computeConditionResult(conditionTriple.getNonPositiveValues()); + boolean condNew = ExpressionUtil.computeConditionResult(conditionTriple.getNonNegativeValues()); + PlusMinusZero condMode = ExpressionUtil.computeConditionResultMode(condOld, condNew); + if (condMode == null || (condMode == PlusMinusZero.ZERO && !condNew)) { + LOGGER.trace("Skipping evaluation of "+assignmentType+" because of condition result"); + assignmentPath.remove(assignmentPathSegment); + evalAssignment.setValid(false); + return; + } + mode = PlusMinusZero.compute(mode, condMode); + } + boolean isValid = LensUtil.isValid(assignmentType, now, activationComputer); if (isValid || assignmentPathSegment.isValidityOverride()) { if (assignmentType.getConstruction() != null) { if (evaluateConstructions && assignmentPathSegment.isEvaluateConstructions()) { - prepareConstructionEvaluation(evalAssignment, assignmentPathSegment, evaluateOld, source, sourceDescription, + prepareConstructionEvaluation(evalAssignment, assignmentPathSegment, evaluateOld, mode, source, sourceDescription, assignmentPath, assignmentPathSegment.getOrderOneObject(), task, result); } @@ -269,7 +287,7 @@ private void evaluateAssignment(EvaluatedAssignment evalAssignment, Assignmen } else if (target != null) { - evaluateTarget(evalAssignment, assignmentPathSegment, evaluateOld, target, source, assignmentType.getTargetRef().getRelation(), sourceDescription, + evaluateTarget(evalAssignment, assignmentPathSegment, evaluateOld, mode, target, source, assignmentType.getTargetRef().getRelation(), sourceDescription, assignmentPath, task, result); } else { @@ -288,7 +306,7 @@ private void evaluateAssignment(EvaluatedAssignment evalAssignment, Assignmen } private void prepareConstructionEvaluation(EvaluatedAssignment evaluatedAssignment, AssignmentPathSegment assignmentPathSegment, - boolean evaluateOld, ObjectType source, String sourceDescription, + boolean evaluateOld, PlusMinusZero mode, ObjectType source, String sourceDescription, AssignmentPath assignmentPath, ObjectType orderOneObject, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException { assertSource(source, evaluatedAssignment); @@ -310,8 +328,17 @@ private void prepareConstructionEvaluation(EvaluatedAssignment evaluatedAssig construction.setOrderOneObject(orderOneObject); // Do not evaluate the construction here. We will do it in the second pass. Just prepare everything to be evaluated. - - evaluatedAssignment.addConstructionZero(construction); + switch (mode) { + case PLUS: + evaluatedAssignment.addConstructionPlus(construction); + break; + case ZERO: + evaluatedAssignment.addConstructionZero(construction); + break; + case MINUS: + evaluatedAssignment.addConstructionMinus(construction); + break; + } } private void evaluateFocusMappings(EvaluatedAssignment evaluatedAssignment, AssignmentPathSegment assignmentPathSegment, @@ -373,15 +400,15 @@ private PrismObject resolveTarget(AssignmentType assignmentType, ObjectType s private void evaluateTarget(EvaluatedAssignment assignment, AssignmentPathSegment assignmentPathSegment, - boolean evaluateOld, PrismObject target, ObjectType source, QName relation, String sourceDescription, + boolean evaluateOld, PlusMinusZero mode, PrismObject target, ObjectType source, QName relation, String sourceDescription, AssignmentPath assignmentPath, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { assertSource(source, assignment); ObjectType targetType = (ObjectType) target.asObjectable(); assignmentPathSegment.setTarget(targetType); if (targetType instanceof AbstractRoleType) { - evaluateAbstractRole(assignment, assignmentPathSegment, evaluateOld, (AbstractRoleType)targetType, source, sourceDescription, + boolean roleConditionTrue = evaluateAbstractRole(assignment, assignmentPathSegment, evaluateOld, mode, (AbstractRoleType)targetType, source, sourceDescription, assignmentPath, task, result); - if (targetType instanceof OrgType && assignmentPath.getEvaluationOrder() == 1) { + if (roleConditionTrue && mode != PlusMinusZero.MINUS && targetType instanceof OrgType && assignmentPath.getEvaluationOrder() == 1) { PrismReferenceValue refVal = new PrismReferenceValue(); refVal.setObject(targetType.asPrismObject()); refVal.setRelation(relation); @@ -393,18 +420,21 @@ private void evaluateTarget(EvaluatedAssignment assignment, AssignmentPathSeg } private boolean evaluateAbstractRole(EvaluatedAssignment assignment, AssignmentPathSegment assignmentPathSegment, - boolean evaluateOld, AbstractRoleType roleType, ObjectType source, String sourceDescription, + boolean evaluateOld, PlusMinusZero mode, AbstractRoleType roleType, ObjectType source, String sourceDescription, AssignmentPath assignmentPath, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { assertSource(source, assignment); MappingType conditionType = roleType.getCondition(); if (conditionType != null) { - DeltaSetTriple conditionTriple = evaluateMappingAsCondition(conditionType, source, task, result); - if (conditionTriple != null) { - // TODO - - + PrismValueDeltaSetTriple> conditionTriple = evaluateMappingAsCondition(conditionType, source, task, result); + boolean condOld = ExpressionUtil.computeConditionResult(conditionTriple.getNonPositiveValues()); + boolean condNew = ExpressionUtil.computeConditionResult(conditionTriple.getNonNegativeValues()); + PlusMinusZero condMode = ExpressionUtil.computeConditionResultMode(condOld, condNew); + if (condMode == null || (condMode == PlusMinusZero.ZERO && !condNew)) { + LOGGER.trace("Skipping evaluation of "+roleType+" because of condition result"); + return false; } + mode = PlusMinusZero.compute(mode, condMode); } int evaluationOrder = assignmentPath.getEvaluationOrder(); @@ -438,7 +468,7 @@ private boolean evaluateAbstractRole(EvaluatedAssignment assignment, Assignme roleAssignmentPathSegment.setEvaluateConstructions(true); roleAssignmentPathSegment.setEvaluationOrder(evaluationOrder); roleAssignmentPathSegment.setOrderOneObject(orderOneObject); - evaluateAssignment(assignment, roleAssignmentPathSegment, evaluateOld, roleType, subSourceDescription, assignmentPath, task, result); + evaluateAssignment(assignment, roleAssignmentPathSegment, evaluateOld, mode, roleType, subSourceDescription, assignmentPath, task, result); // } else if (inducementOrder < assignmentPath.getEvaluationOrder()) { // LOGGER.trace("Follow({}) inducement({}) in role {}", // new Object[]{evaluationOrder, inducementOrder, source}); @@ -466,14 +496,14 @@ private boolean evaluateAbstractRole(EvaluatedAssignment assignment, Assignme roleAssignmentPathSegment.setEvaluateConstructions(false); roleAssignmentPathSegment.setEvaluationOrder(evaluationOrder+1); roleAssignmentPathSegment.setOrderOneObject(orderOneObject); - evaluateAssignment(assignment, roleAssignmentPathSegment, evaluateOld, roleType, subSourceDescription, assignmentPath, task, result); + evaluateAssignment(assignment, roleAssignmentPathSegment, evaluateOld, mode, roleType, subSourceDescription, assignmentPath, task, result); } for(AuthorizationType authorizationType: roleType.getAuthorization()) { Authorization authorization = createAuthorization(authorizationType); assignment.addAuthorization(authorization); } - return true; + return mode != PlusMinusZero.MINUS; } public static String dumpAssignment(AssignmentType assignmentType) { @@ -530,7 +560,7 @@ private void checkSchema(AssignmentType assignmentType, String sourceDescription } } - public DeltaSetTriple evaluateMappingAsCondition(MappingType conditionType, ObjectType source, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { + public PrismValueDeltaSetTriple> evaluateMappingAsCondition(MappingType conditionType, ObjectType source, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { Mapping> mapping = mappingFactory.createMapping(conditionType, "condition in " + source); @@ -549,16 +579,7 @@ public DeltaSetTriple evaluateMappingAsCondition(MappingType conditionT LensUtil.evaluateMapping(mapping, lensContext, task, result); - PrismValueDeltaSetTriple> mappingOutputTriple = mapping.getOutputTriple(); - DeltaSetTriple outputTriple = new DeltaSetTriple<>(); - Transformer, Boolean> transformer = new Transformer, Boolean>() { - @Override - public Boolean transform(PrismPropertyValue in) { - return in.getValue(); - } - }; - mappingOutputTriple.transform(outputTriple, transformer); - return outputTriple; + return (PrismValueDeltaSetTriple>) mapping.getOutputTriple(); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java index b78881a96f3..fb5cb55d115 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/EvaluatedAssignment.java @@ -87,6 +87,14 @@ public void addConstructionZero(Construction contruction) { constructions.addToZeroSet(contruction); } + public void addConstructionPlus(Construction contruction) { + constructions.addToPlusSet(contruction); + } + + public void addConstructionMinus(Construction contruction) { + constructions.addToMinusSet(contruction); + } + public Collection getOrgRefVals() { return orgRefVals; } diff --git a/model/model-intest/src/test/resources/rbac/role-wannabe.xml b/model/model-intest/src/test/resources/rbac/role-wannabe.xml index e2e72ad8484..5db9afad181 100644 --- a/model/model-intest/src/test/resources/rbac/role-wannabe.xml +++ b/model/model-intest/src/test/resources/rbac/role-wannabe.xml @@ -49,7 +49,7 @@ @@ -63,7 +63,7 @@ From c93a8eeeb0aa4278fcd8c945a77ee2a299121551 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Thu, 31 Jul 2014 14:40:25 +0200 Subject: [PATCH 45/51] Assignment conditions fixed, more tests, diag improvements. --- .../expression/script/ScriptExpression.java | 9 +- .../model/impl/lens/AssignmentEvaluator.java | 30 ++++- .../model/impl/lens/AssignmentPath.java | 16 ++- .../model/impl/lens/Construction.java | 8 +- .../midpoint/model/intest/TestRbac.java | 110 +++++++++++++++++- .../src/test/resources/common/user-jack.xml | 3 +- .../src/test/resources/logback-test.xml | 1 + 7 files changed, 161 insertions(+), 16 deletions(-) diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpression.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpression.java index 6969aab65d2..780ff491735 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpression.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpression.java @@ -32,6 +32,7 @@ import com.evolveum.midpoint.schema.util.ObjectResolver; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.DebugDumpable; +import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; @@ -65,6 +66,7 @@ public class ScriptExpression { private Collection functions; private static final Trace LOGGER = TraceManager.getTrace(ScriptExpression.class); + private static final int MAX_CODE_CHARS = 42; ScriptExpression(ScriptEvaluator evaluator, ScriptExpressionEvaluatorType scriptType) { this.scriptType = scriptType; @@ -166,7 +168,7 @@ private String formatVariables(ExpressionVariables variables) { } private String formatCode() { - return scriptType.getCode(); + return DebugUtil.excerpt(scriptType.getCode().replaceAll("[\\s\\r\\n]+", " "), MAX_CODE_CHARS); } public ItemPath parsePath(String path) { @@ -184,4 +186,9 @@ public ItemPath parsePath(String path) { // return xPathHolder.toItemPath(); } + @Override + public String toString() { + return "ScriptExpression(" + formatCode() + ")"; + } + } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java index e69f0e3af97..09526c67c59 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentEvaluator.java @@ -255,17 +255,22 @@ private void evaluateAssignment(EvaluatedAssignment evalAssignment, Assignmen MappingType conditionType = assignmentType.getCondition(); if (conditionType != null) { - PrismValueDeltaSetTriple> conditionTriple = evaluateMappingAsCondition(conditionType, source, task, result); + PrismValueDeltaSetTriple> conditionTriple = evaluateMappingAsCondition(conditionType, + assignmentType, source, task, result); boolean condOld = ExpressionUtil.computeConditionResult(conditionTriple.getNonPositiveValues()); boolean condNew = ExpressionUtil.computeConditionResult(conditionTriple.getNonNegativeValues()); PlusMinusZero condMode = ExpressionUtil.computeConditionResultMode(condOld, condNew); if (condMode == null || (condMode == PlusMinusZero.ZERO && !condNew)) { - LOGGER.trace("Skipping evaluation of "+assignmentType+" because of condition result"); + LOGGER.trace("Skipping evaluation of "+assignmentType+" because of condition result ({} -> {}: {})", + new Object[]{ condOld, condNew, condMode }); assignmentPath.remove(assignmentPathSegment); evalAssignment.setValid(false); return; } + PlusMinusZero origMode = mode; mode = PlusMinusZero.compute(mode, condMode); + LOGGER.trace("Evaluated condition in assignment {} -> {}: {} + {} = {}", new Object[]{ + condOld, condNew, origMode, condMode, mode }); } boolean isValid = LensUtil.isValid(assignmentType, now, activationComputer); @@ -426,15 +431,21 @@ private boolean evaluateAbstractRole(EvaluatedAssignment assignment, Assignme MappingType conditionType = roleType.getCondition(); if (conditionType != null) { - PrismValueDeltaSetTriple> conditionTriple = evaluateMappingAsCondition(conditionType, source, task, result); + PrismValueDeltaSetTriple> conditionTriple = evaluateMappingAsCondition(conditionType, + null, source, task, result); boolean condOld = ExpressionUtil.computeConditionResult(conditionTriple.getNonPositiveValues()); boolean condNew = ExpressionUtil.computeConditionResult(conditionTriple.getNonNegativeValues()); PlusMinusZero condMode = ExpressionUtil.computeConditionResultMode(condOld, condNew); if (condMode == null || (condMode == PlusMinusZero.ZERO && !condNew)) { - LOGGER.trace("Skipping evaluation of "+roleType+" because of condition result"); + LOGGER.trace("Skipping evaluation of "+roleType+" because of condition result ({} -> {}: {})", + new Object[]{ condOld, condNew, condMode }); return false; } + PlusMinusZero origMode = mode; mode = PlusMinusZero.compute(mode, condMode); + LOGGER.trace("Evaluated condition in {}: {} -> {}: {} + {} = {}", new Object[]{ + roleType, condOld, condNew, origMode, condMode, mode }); + } int evaluationOrder = assignmentPath.getEvaluationOrder(); @@ -560,9 +571,16 @@ private void checkSchema(AssignmentType assignmentType, String sourceDescription } } - public PrismValueDeltaSetTriple> evaluateMappingAsCondition(MappingType conditionType, ObjectType source, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { + public PrismValueDeltaSetTriple> evaluateMappingAsCondition(MappingType conditionType, + AssignmentType sourceAssignment, ObjectType source, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { + String desc; + if (sourceAssignment == null) { + desc = "condition in " + source; + } else { + desc = "condition in assignment in " + source; + } Mapping> mapping = mappingFactory.createMapping(conditionType, - "condition in " + source); + desc); mapping.addVariableDefinition(ExpressionConstants.VAR_USER, focusOdo); mapping.addVariableDefinition(ExpressionConstants.VAR_FOCUS, focusOdo); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPath.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPath.java index 876b021572f..ebf4a0f7e2d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPath.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/AssignmentPath.java @@ -127,8 +127,20 @@ public String debugDump() { public String debugDump(int indent) { StringBuilder sb = new StringBuilder(); DebugUtil.debugDumpLabel(sb, "AssignmentPath", indent); - sb.append("\n"); - DebugUtil.debugDump(segments, indent + 1); + if (segments == null || segments.isEmpty()) { + sb.append(" (empty)"); + } else { + sb.append(" (").append(segments.size()).append(")"); + if (DebugUtil.isDetailedDebugDump()) { + DebugUtil.debugDump(sb, segments, indent + 1, false); + } else { + for (AssignmentPathSegment segment: segments) { + sb.append("\n"); + DebugUtil.indentDebugDump(sb, indent + 1); + sb.append(segment.toString()); + } + } + } return sb.toString(); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java index d8e6540b303..4f63a37c5bc 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java @@ -546,7 +546,7 @@ public String debugDump(int indent) { StringBuilder sb = new StringBuilder(); DebugUtil.debugDumpLabel(sb, "Construction", indent); if (refinedObjectClassDefinition == null) { - sb.append("null"); + sb.append(" (no object class definition)"); } else { sb.append(refinedObjectClassDefinition.getShadowDiscriminator()); } @@ -566,8 +566,10 @@ public String debugDump(int indent) { sb.append(mapping.debugDump(indent+2)); } } - sb.append("\n"); - DebugUtil.debugDumpWithLabel(sb, "assignmentPath", assignmentPath, indent + 1); + if (assignmentPath != null) { + sb.append("\n"); + sb.append(assignmentPath.debugDump(indent+1)); + } return sb.toString(); } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java index cdfea21c353..2dbc2fad62f 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestRbac.java @@ -1065,6 +1065,32 @@ public void test540JackAssignRoleWannabe() throws Exception { result.computeStatus(); TestUtil.assertSuccess(result); + assertAssignedRole(USER_JACK_OID, ROLE_WANNABE_OID, task, result); + assertNoDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME); + } + + /** + * Remove honorifixSuffix. This triggers a condition in Wannabe role inducement. + * But as the whole role has false condition nothing should happen. + */ + @Test + public void test541JackRemoveHonorificSuffixWannabe() throws Exception { + final String TEST_NAME = "test541JackRemoveHonorificSuffixWannabe"; + TestUtil.displayTestTile(this, TEST_NAME); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modifyUserReplace(USER_JACK_OID, UserType.F_HONORIFIC_SUFFIX, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + assertAssignedRole(USER_JACK_OID, ROLE_WANNABE_OID, task, result); assertNoDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME); } @@ -1073,8 +1099,8 @@ public void test540JackAssignRoleWannabe() throws Exception { * Modify employeeType. This triggers a condition in Wannabe role. */ @Test - public void test541JackModifyEmployeeTypeWannabe() throws Exception { - final String TEST_NAME = "test541JackModifyEmployeeTypeWannabe"; + public void test542JackModifyEmployeeTypeWannabe() throws Exception { + final String TEST_NAME = "test542JackModifyEmployeeTypeWannabe"; TestUtil.displayTestTile(this, TEST_NAME); assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); @@ -1095,6 +1121,86 @@ public void test541JackModifyEmployeeTypeWannabe() throws Exception { assertDefaultDummyAccountAttribute(ACCOUNT_JACK_DUMMY_USERNAME, "title", "Wannabe Cpt. Where's the rum?"); } + /** + * Remove honorifixPrefix. This triggers a condition in Wannabe role and should remove an account. + */ + @Test + public void test543JackRemoveHonorificPrefixWannabe() throws Exception { + final String TEST_NAME = "test543JackRemoveHonorificPrefixWannabe"; + TestUtil.displayTestTile(this, TEST_NAME); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modifyUserReplace(USER_JACK_OID, UserType.F_HONORIFIC_PREFIX, task, result); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertAssignedRole(USER_JACK_OID, ROLE_WANNABE_OID, task, result); + assertNoDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME); + } + + /** + * Set honorifixSuffix. This triggers conditions and adds a sub-role Honorable Wannabe. + */ + @Test + public void test544JackSetHonorificSuffixWannabe() throws Exception { + final String TEST_NAME = "test544JackSetHonorificSuffixWannabe"; + TestUtil.displayTestTile(this, TEST_NAME); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modifyUserReplace(USER_JACK_OID, UserType.F_HONORIFIC_SUFFIX, task, result, + PrismTestUtil.createPolyString("PhD.")); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertAssignedRole(USER_JACK_OID, ROLE_WANNABE_OID, task, result); + assertDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME, ACCOUNT_JACK_DUMMY_FULLNAME, true); + assertDefaultDummyAccountAttribute(ACCOUNT_JACK_DUMMY_USERNAME, + DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_QUOTE_NAME, "Arr!", "Whatever. -- jack"); + } + + /** + * Restore honorifixPrefix. The title should be replaced again. + */ + @Test + public void test545JackRestoreHonorificPrefixWannabe() throws Exception { + final String TEST_NAME = "test545JackRestoreHonorificPrefixWannabe"; + TestUtil.displayTestTile(this, TEST_NAME); + assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + + // WHEN + TestUtil.displayWhen(TEST_NAME); + modifyUserReplace(USER_JACK_OID, UserType.F_HONORIFIC_PREFIX, task, result, + PrismTestUtil.createPolyString("captain")); + + // THEN + TestUtil.displayThen(TEST_NAME); + result.computeStatus(); + TestUtil.assertSuccess(result); + + assertAssignedRole(USER_JACK_OID, ROLE_WANNABE_OID, task, result); + assertDummyAccount(ACCOUNT_JACK_DUMMY_USERNAME, ACCOUNT_JACK_DUMMY_FULLNAME, true); + assertDefaultDummyAccountAttribute(ACCOUNT_JACK_DUMMY_USERNAME, "title", "Wannabe captain Where's the rum?"); + } + /** * The account should be gone - regardless of the condition state. */ diff --git a/model/model-intest/src/test/resources/common/user-jack.xml b/model/model-intest/src/test/resources/common/user-jack.xml index c119dd1822c..c12293c02cd 100644 --- a/model/model-intest/src/test/resources/common/user-jack.xml +++ b/model/model-intest/src/test/resources/common/user-jack.xml @@ -1,6 +1,6 @@ - - + + - + - + @@ -59,7 +59,7 @@ - + From 3f264a19d8d39d50dbd5273964a72154aa6aead2 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Thu, 31 Jul 2014 16:36:00 +0200 Subject: [PATCH 47/51] Moving displayName and identifier from OrgType to AbstractRoleType --- .../xml/ns/public/common/common-3.xsd | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd index 9501f88dd18..56dacab40f8 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd @@ -6041,6 +6041,35 @@ + + + + Human-readable name of the role or org. It may be quite long, container national characters + and there is no uniqueness requirement. + + + Display Name + 100 + + + + + + + + Identifier of the role or org. It should be a structured information usually used for + refering to the role or org or correlating it in various systems. E.g. numeric organizational + unit identifier, role code, etc. It should be unique in its "own" scope. E.g. an organizational + unit identifier should be unique in the scope of all organizational units but it may conflict + with an identifier of a project. + + + Identifier + 110 + + + + @@ -6717,35 +6746,7 @@ - - - - Human-readable name of the org. It may be quite long, container national characters - and there is no uniqueness requirement. - - - Display Name - 100 - - - - - - - - Identifier of the org. It should be a structured information usually used for - refering to the org or correlating it in various systems. E.g. numeric organizational - unit identifier. It should be unique in its "own" scope. E.g. an organizational unit identifier - should be unique in the scope of all organizational units but it may conflict with an - identifier of a project. - - - Identifier - 110 - - - - + From 95bd72e47064d5fba2e5aa216059ec2f9deaab7b Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Thu, 31 Jul 2014 16:50:00 +0200 Subject: [PATCH 48/51] Cleaning up MatchingRule methods (MID-1926) --- .../com/evolveum/midpoint/prism/match/DefaultMatchingRule.java | 2 +- .../java/com/evolveum/midpoint/prism/match/MatchingRule.java | 2 +- .../midpoint/prism/match/PolyStringNormMatchingRule.java | 2 +- .../midpoint/prism/match/PolyStringOrigMatchingRule.java | 2 +- .../midpoint/prism/match/PolyStringStrictMatchingRule.java | 2 +- .../midpoint/prism/match/StringIgnoreCaseMatchingRule.java | 2 +- .../java/com/evolveum/midpoint/prism/query/SubstringFilter.java | 2 +- .../midpoint/model/impl/lens/projector/ValueMatcher.java | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/DefaultMatchingRule.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/DefaultMatchingRule.java index 4d79edf6ba5..a80ba80cfc9 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/DefaultMatchingRule.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/DefaultMatchingRule.java @@ -77,7 +77,7 @@ public T normalize(T original) { } @Override - public boolean matches(T a, String regex) { + public boolean matchRegex(T a, String regex) { String valueToMatch = null; if (a instanceof Matchable){ return ((Matchable) a).matches(regex); diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/MatchingRule.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/MatchingRule.java index 23c4016e120..62545bf3182 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/MatchingRule.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/MatchingRule.java @@ -48,7 +48,7 @@ public interface MatchingRule { /** * Matches value against given regex. */ - boolean matches(T a, String regex); + boolean matchRegex(T a, String regex); /** * Returns a normalized version of the value. diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringNormMatchingRule.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringNormMatchingRule.java index 26c10c8db81..34188aad427 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringNormMatchingRule.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringNormMatchingRule.java @@ -71,7 +71,7 @@ public PolyString normalize(PolyString original) { } @Override - public boolean matches(PolyString a, String regex) { + public boolean matchRegex(PolyString a, String regex) { if (a == null){ return false; } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringOrigMatchingRule.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringOrigMatchingRule.java index 0916349fc39..84b690f4184 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringOrigMatchingRule.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringOrigMatchingRule.java @@ -71,7 +71,7 @@ public PolyString normalize(PolyString original) { } @Override - public boolean matches(PolyString a, String regex) { + public boolean matchRegex(PolyString a, String regex) { if (a == null){ return false; } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringStrictMatchingRule.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringStrictMatchingRule.java index 56a670a8e53..e6dd9a71222 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringStrictMatchingRule.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/PolyStringStrictMatchingRule.java @@ -71,7 +71,7 @@ public PolyString normalize(PolyString original) { } @Override - public boolean matches(PolyString a, String regex) { + public boolean matchRegex(PolyString a, String regex) { if (a == null){ return false; } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/StringIgnoreCaseMatchingRule.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/StringIgnoreCaseMatchingRule.java index 3088fbc694f..903dbeb8e6d 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/StringIgnoreCaseMatchingRule.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/match/StringIgnoreCaseMatchingRule.java @@ -68,7 +68,7 @@ public String normalize(String original) { } @Override - public boolean matches(String a, String regex) { + public boolean matchRegex(String a, String regex) { if (a == null){ return false; } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/SubstringFilter.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/SubstringFilter.java index 5fed3f8d7a8..d2b22960d6d 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/SubstringFilter.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/SubstringFilter.java @@ -247,7 +247,7 @@ public boolean match(PrismObject object, MatchingRuleR if (!anchorEnd) { sb.append(".*"); } - if (matching.matches(value, sb.toString())){ + if (matching.matchRegex(value, sb.toString())){ return true; } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ValueMatcher.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ValueMatcher.java index 72735e54290..ce3ff58d60f 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ValueMatcher.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ValueMatcher.java @@ -54,7 +54,7 @@ public boolean match(T realA, T realB) { } public boolean matches(T realValue, String regex){ - return matchingRule.matches(realValue, regex); + return matchingRule.matchRegex(realValue, regex); } public boolean hasRealValue(PrismProperty property, PrismPropertyValue pValue) { From 99cec3bbef91a2f8ec6d9be84b562626683e94e6 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Thu, 31 Jul 2014 16:55:34 +0200 Subject: [PATCH 49/51] Fixing the tests after assignment schema change. --- .../java/com/evolveum/midpoint/schema/util/SchemaTestUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/schema/src/test/java/com/evolveum/midpoint/schema/util/SchemaTestUtil.java b/infra/schema/src/test/java/com/evolveum/midpoint/schema/util/SchemaTestUtil.java index 69ae281c08a..ab6160c3fde 100644 --- a/infra/schema/src/test/java/com/evolveum/midpoint/schema/util/SchemaTestUtil.java +++ b/infra/schema/src/test/java/com/evolveum/midpoint/schema/util/SchemaTestUtil.java @@ -96,7 +96,7 @@ public static void assertFocusDefinition(ComplexTypeDefinition complexTypeDefini PrismContainerDefinition assignmentContainer = complexTypeDefinition.findContainerDefinition(UserType.F_ASSIGNMENT); PrismAsserts.assertDefinition(assignmentContainer, UserType.F_ASSIGNMENT, AssignmentType.COMPLEX_TYPE, 0, -1); assertFalse("Assignment is runtime", assignmentContainer.isRuntimeSchema()); - assertEquals("Assignment size", 9, assignmentContainer.getDefinitions().size()); + assertEquals("Assignment size", 10, assignmentContainer.getDefinitions().size()); PrismContainerDefinition constructionContainer = assignmentContainer.findContainerDefinition(AssignmentType.F_CONSTRUCTION); PrismAsserts.assertDefinition(constructionContainer, AssignmentType.F_CONSTRUCTION, ConstructionType.COMPLEX_TYPE, 0, 1); From 7b97a69ad0909d99aabbb0630737b8873f0fb705 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Thu, 31 Jul 2014 17:53:47 +0200 Subject: [PATCH 50/51] Fixing user login with conditional roles (+test) --- .../ModelExpressionThreadLocalHolder.java | 1 + .../midpoint/model/impl/lens/LensContext.java | 4 + .../impl/lens/LensContextPlaceholder.java | 54 +++++++++++++ .../impl/security/UserProfileServiceImpl.java | 18 ++++- ...bstractConfiguredModelIntegrationTest.java | 2 + .../midpoint/model/intest/TestSecurity.java | 79 +++++++++++++++++++ .../resources/security/role-conditional.xml | 35 ++++++++ 7 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContextPlaceholder.java create mode 100644 model/model-intest/src/test/resources/security/role-conditional.xml diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/ModelExpressionThreadLocalHolder.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/ModelExpressionThreadLocalHolder.java index f1592437cc3..dcbd7aa2cb5 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/ModelExpressionThreadLocalHolder.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/ModelExpressionThreadLocalHolder.java @@ -19,6 +19,7 @@ import java.util.Deque; import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.model.impl.lens.LensContextPlaceholder; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java index 0e770fcc9ea..56fb19727d8 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java @@ -125,6 +125,10 @@ public LensContext(Class focusClass, PrismContext prismContext, ProvisioningS this.focusClass = focusClass; } + protected LensContext(PrismContext prismContext) { + this.prismContext = prismContext; + } + public PrismContext getPrismContext() { return prismContext; } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContextPlaceholder.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContextPlaceholder.java new file mode 100644 index 00000000000..69ab206bc9f --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContextPlaceholder.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2014 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.lens; + +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; + +/** + * This class does nothing. It just takes place when no real Lens Context is available. + * @see ModelExpressionThreadLocalHolder + * + * @author semancik + * + */ +public class LensContextPlaceholder extends LensContext { + + public LensContextPlaceholder(PrismContext prismContext) { + super(prismContext); + } + + @Override + public String toString() { + return "LensContextPlaceholder()"; + } + + @Override + public String dump(boolean showTriples) { + return "LensContextPlaceholder()"; + } + + @Override + public String debugDump(int indent, boolean showTriples) { + StringBuilder sb = new StringBuilder(); + DebugUtil.indentDebugDump(sb, indent); + sb.append("LensContextPlaceholder"); + return sb.toString(); + } + + +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/UserProfileServiceImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/UserProfileServiceImpl.java index 0f740b36458..26d96377457 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/UserProfileServiceImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/security/UserProfileServiceImpl.java @@ -25,6 +25,8 @@ import com.evolveum.midpoint.model.impl.UserComputer; import com.evolveum.midpoint.model.impl.lens.AssignmentEvaluator; import com.evolveum.midpoint.model.impl.lens.EvaluatedAssignment; +import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.model.impl.lens.LensContextPlaceholder; import com.evolveum.midpoint.model.impl.lens.LensUtil; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismContext; @@ -41,6 +43,8 @@ import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.UserProfileService; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; @@ -84,6 +88,9 @@ public class UserProfileServiceImpl implements UserProfileService { @Autowired(required = true) private PrismContext prismContext; + + @Autowired(required = true) + private TaskManager taskManager; @Override public MidPointPrincipal getPrincipal(String username) throws ObjectNotFoundException { @@ -169,18 +176,25 @@ private void addAuthorizations(MidPointPrincipal principal) { assignmentEvaluator.setMappingFactory(valueConstructionFactory); assignmentEvaluator.setActivationComputer(activationComputer); assignmentEvaluator.setNow(clock.currentTimeXMLGregorianCalendar()); + // We do need only authorizations. Therefore we not need to evaluate constructions, // so switching it off is faster. It also avoids nasty problems with resources being down, // resource schema not available, etc. assignmentEvaluator.setEvaluateConstructions(false); + + // We do not have real lens context here. But the push methods in ModelExpressionThreadLocalHolder + // will need something to push on the stack. So give them context placeholder. + LensContext lensContext = new LensContextPlaceholder<>(prismContext); + assignmentEvaluator.setLensContext(lensContext); - OperationResult result = new OperationResult(UserProfileServiceImpl.class.getName() + ".addAuthorizations"); + Task task = taskManager.createTaskInstance(UserProfileServiceImpl.class.getName() + ".addAuthorizations"); + OperationResult result = task.getResult(); for(AssignmentType assignmentType: userType.getAssignment()) { try { ItemDeltaItem> assignmentIdi = new ItemDeltaItem<>(); assignmentIdi.setItemOld(LensUtil.createAssignmentSingleValueContainerClone(assignmentType)); assignmentIdi.recompute(); - EvaluatedAssignment assignment = assignmentEvaluator.evaluate(assignmentIdi, false, userType, userType.toString(), null, result); + EvaluatedAssignment assignment = assignmentEvaluator.evaluate(assignmentIdi, false, userType, userType.toString(), task, result); if (assignment.isValid()) { authorizations.addAll(assignment.getAuthorizations()); } 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 b0bd267cfff..cc914bb7e34 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 @@ -327,6 +327,8 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractModelIntegra protected static final String AUTZ_COMMAND_URL = QNameUtil.qNameToUri(AUTZ_COMMAND_QNAME); protected static final QName AUTZ_PUNISH_QNAME = new QName(NS_TEST_AUTZ, "punish"); protected static final String AUTZ_PUNISH_URL = QNameUtil.qNameToUri(AUTZ_PUNISH_QNAME); + protected static final QName AUTZ_CAPSIZE_QNAME = new QName(NS_TEST_AUTZ, "capsize"); + protected static final String AUTZ_CAPSIZE_URL = QNameUtil.qNameToUri(AUTZ_CAPSIZE_QNAME); private static final Trace LOGGER = TraceManager.getTrace(AbstractConfiguredModelIntegrationTest.class); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java index 32a9d0554b0..0c4c524bdea 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java @@ -184,6 +184,9 @@ public class TestSecurity extends AbstractInitializedModelIntegrationTest { protected static final File ROLE_BUSINESS_1_FILE = new File(TEST_DIR, "role-business-1.xml"); protected static final String ROLE_BUSINESS_1_OID = "00000000-0000-0000-0000-00000000aab1"; + + protected static final File ROLE_CONDITIONAL_FILE = new File(TEST_DIR, "role-conditional.xml"); + protected static final String ROLE_CONDITIONAL_OID = "00000000-0000-0000-0000-00000000aac1"; private static final String LOG_PREFIX_FAIL = "SSSSS=X "; private static final String LOG_PREFIX_ATTEMPT = "SSSSS=> "; @@ -220,6 +223,8 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti repoAddObjectFromFile(ROLE_APPLICATION_2_FILE, RoleType.class, initResult); repoAddObjectFromFile(ROLE_BUSINESS_1_FILE, RoleType.class, initResult); + repoAddObjectFromFile(ROLE_CONDITIONAL_FILE, RoleType.class, initResult); + assignOrg(USER_GUYBRUSH_OID, ORG_SWASHBUCKLER_SECTION_OID, initTask, initResult); PrismObject userRum = createUser(USER_RUM_ROGERS_NAME, "Rum Rogers"); @@ -344,6 +349,80 @@ public void test052GetUserGuybrush() throws Exception { assertNotAuthorized(principal, AUTZ_COMMAND_URL); } + @Test + public void test060GuybrushConditionalRoleFalse() throws Exception { + final String TEST_NAME = "test060GuybrushConditionalRoleFalse"; + TestUtil.displayTestTile(this, TEST_NAME); + assertLoggedInUser(USER_ADMINISTRATOR_USERNAME); + + assignRole(USER_GUYBRUSH_OID, ROLE_CONDITIONAL_OID); + + // WHEN + MidPointPrincipal principal = userProfileService.getPrincipal(USER_GUYBRUSH_USERNAME); + + // THEN + display("Principal guybrush", principal); + assertEquals("wrong username", USER_GUYBRUSH_USERNAME, principal.getUsername()); + assertEquals("wrong oid", USER_GUYBRUSH_OID, principal.getOid()); + assertTrue("Unexpected authorizations", principal.getAuthorities().isEmpty()); + display("User in principal guybrush", principal.getUser().asPrismObject()); + + principal.getUser().asPrismObject().checkConsistence(true, true); + + assertNotAuthorized(principal, AUTZ_LOOT_URL); + assertNotAuthorized(principal, AUTZ_COMMAND_URL); + } + + @Test + public void test061GuybrushConditionalRoleTrue() throws Exception { + final String TEST_NAME = "test061GuybrushConditionalRoleTrue"; + TestUtil.displayTestTile(this, TEST_NAME); + assertLoggedInUser(USER_ADMINISTRATOR_USERNAME); + + Task task = taskManager.createTaskInstance(TestRbac.class.getName() + "." + TEST_NAME); + OperationResult result = task.getResult(); + modifyUserReplace(USER_GUYBRUSH_OID, UserType.F_EMPLOYEE_TYPE, task, result, "looser"); + + // WHEN + MidPointPrincipal principal = userProfileService.getPrincipal(USER_GUYBRUSH_USERNAME); + + // THEN + display("Principal guybrush", principal); + assertEquals("wrong username", USER_GUYBRUSH_USERNAME, principal.getUsername()); + assertEquals("wrong oid", USER_GUYBRUSH_OID, principal.getOid()); + assertTrue("Unexpected authorizations", principal.getAuthorities().isEmpty()); + display("User in principal guybrush", principal.getUser().asPrismObject()); + + principal.getUser().asPrismObject().checkConsistence(true, true); + + assertNotAuthorized(principal, AUTZ_LOOT_URL); + assertNotAuthorized(principal, AUTZ_COMMAND_URL); + assertNotAuthorized(principal, AUTZ_CAPSIZE_URL); + } + + @Test + public void test062GuybrushConditionalRoleUnassign() throws Exception { + final String TEST_NAME = "test062GuybrushConditionalRoleUnassign"; + TestUtil.displayTestTile(this, TEST_NAME); + assertLoggedInUser(USER_ADMINISTRATOR_USERNAME); + + unassignRole(USER_GUYBRUSH_OID, ROLE_CONDITIONAL_OID); + + // WHEN + MidPointPrincipal principal = userProfileService.getPrincipal(USER_GUYBRUSH_USERNAME); + + // THEN + display("Principal guybrush", principal); + assertEquals("wrong username", USER_GUYBRUSH_USERNAME, principal.getUsername()); + assertEquals("wrong oid", USER_GUYBRUSH_OID, principal.getOid()); + assertTrue("Unexpected authorizations", principal.getAuthorities().isEmpty()); + display("User in principal guybrush", principal.getUser().asPrismObject()); + + principal.getUser().asPrismObject().checkConsistence(true, true); + + assertNotAuthorized(principal, AUTZ_LOOT_URL); + assertNotAuthorized(principal, AUTZ_COMMAND_URL); + } @Test public void test100JackRolePirate() throws Exception { diff --git a/model/model-intest/src/test/resources/security/role-conditional.xml b/model/model-intest/src/test/resources/security/role-conditional.xml new file mode 100644 index 00000000000..8325a652a56 --- /dev/null +++ b/model/model-intest/src/test/resources/security/role-conditional.xml @@ -0,0 +1,35 @@ + + + Conditional + + http://midpoint.evolveum.com/xml/ns/test/authorization#superspecial + + + + $user/employeeType + + + + + + From 10218beccaf0c8c085a66be8fd9c57d84ded05e3 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Thu, 31 Jul 2014 21:16:46 +0200 Subject: [PATCH 51/51] Fixing schema: making displayName optional --- .../schema/src/main/resources/xml/ns/public/common/common-3.xsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd index 56dacab40f8..622c2b07105 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-3.xsd @@ -6041,7 +6041,7 @@ - + Human-readable name of the role or org. It may be quite long, container national characters