From 21606fa04f2c7a38571d5c996f35f120d2b67b96 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Fri, 27 Jun 2014 00:47:17 +0200 Subject: [PATCH 01/12] Fix for non-functioning WorkItemPage. --- .../web/component/prism/ObjectWrapper.java | 13 ++- .../web/component/util/ObjectWrapperUtil.java | 10 ++- .../web/page/admin/workflow/PageWorkItem.java | 84 +++++++++---------- .../impl/controller/ModelController.java | 11 ++- 4 files changed, 67 insertions(+), 51 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java index 286e40a5ee8..10ef61c8bfc 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java @@ -95,10 +95,11 @@ public class ObjectWrapper implements Serializable { private RefinedObjectClassDefinition objectClassDefinitionForEditing; // a refined definition of an resource object class that reflects its editability; applicable for shadows only public ObjectWrapper(String displayName, String description, PrismObject object, PrismContainerDefinition objectDefinitionForEditing, ContainerStatus status, PageBase pageBase) { - this(displayName, description, object, objectDefinitionForEditing, null, status, pageBase); + this(displayName, description, object, objectDefinitionForEditing, null, status, false, pageBase); } - public ObjectWrapper(String displayName, String description, PrismObject object, PrismContainerDefinition objectDefinitionForEditing, RefinedObjectClassDefinition objectClassDefinitionForEditing, ContainerStatus status, PageBase pageBase) { + // delayContainerCreation is used in cases where caller wants to configure those aspects of the wrapper that must be set before container creation + public ObjectWrapper(String displayName, String description, PrismObject object, PrismContainerDefinition objectDefinitionForEditing, RefinedObjectClassDefinition objectClassDefinitionForEditing, ContainerStatus status, boolean delayContainerCreation, PageBase pageBase) { Validate.notNull(object, "Object must not be null."); Validate.notNull(status, "Container status must not be null."); Validate.notNull(pageBase, "pageBase must not be null."); @@ -110,9 +111,15 @@ public ObjectWrapper(String displayName, String description, PrismObject object, this.objectDefinitionForEditing = objectDefinitionForEditing; this.objectClassDefinitionForEditing = objectClassDefinitionForEditing; - containers = createContainers(pageBase); + if (!delayContainerCreation) { + initializeContainers(pageBase); + } } + public void initializeContainers(PageBase pageBase) { + containers = createContainers(pageBase); + } + public List getAssociations() { return associations; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/util/ObjectWrapperUtil.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/util/ObjectWrapperUtil.java index 98704f3ccb3..55a72bd91f2 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/util/ObjectWrapperUtil.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/util/ObjectWrapperUtil.java @@ -17,8 +17,12 @@ public class ObjectWrapperUtil { - - public static ObjectWrapper createObjectWrapper(String displayName, String description, PrismObject object, ContainerStatus status, PageBase pageBase) { + + public static ObjectWrapper createObjectWrapper(String displayName, String description, PrismObject object, ContainerStatus status, PageBase pageBase) { + return createObjectWrapper(displayName, description, object, status, false, pageBase); + } + + public static ObjectWrapper createObjectWrapper(String displayName, String description, PrismObject object, ContainerStatus status, boolean delayContainerCreation, PageBase pageBase) { try { PrismContainerDefinition objectDefinitionForEditing = pageBase.getModelInteractionService().getEditObjectDefinition(object); RefinedObjectClassDefinition objectClassDefinitionForEditing = null; @@ -28,7 +32,7 @@ public static ObjectWrapper createObjectWrapper(String di objectClassDefinitionForEditing = pageBase.getModelInteractionService().getEditObjectClassDefinition((PrismObject) object, resource); } - ObjectWrapper wrapper = new ObjectWrapper(displayName, description, object, objectDefinitionForEditing, objectClassDefinitionForEditing, status, pageBase); + ObjectWrapper wrapper = new ObjectWrapper(displayName, description, object, objectDefinitionForEditing, objectClassDefinitionForEditing, status, delayContainerCreation, pageBase); return wrapper; } catch (SchemaException ex){ throw new SystemException(ex); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItem.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItem.java index 3ee8c308b08..36030ff9881 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItem.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItem.java @@ -216,14 +216,15 @@ private ObjectWrapper getRequesterWrapper() { ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper( createStringResource("pageWorkItem.requester.description").getString(), // name (large font) PolyString.getOrig(prism.asObjectable().getName()), // description (smaller font) - prism, status, this); - if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { - showResultInSession(wrapper.getResult()); - } + prism, status, true, this); wrapper.setShowEmpty(false); wrapper.setMinimalized(true); wrapper.setShowAssignments(false); wrapper.setReadonly(true); + wrapper.initializeContainers(this); + if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { + showResultInSession(wrapper.getResult()); + } return wrapper; @@ -244,14 +245,15 @@ private ObjectWrapper getObjectOldWrapper() { ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper( createStringResource("pageWorkItem.objectOld.description").getString(), // name (large font) PolyString.getOrig(prism.asObjectable().getName()), // description (smaller font) - prism, status, this); - if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { - showResultInSession(wrapper.getResult()); - } + prism, status, true, this); wrapper.setShowEmpty(false); wrapper.setMinimalized(true); wrapper.setShowAssignments(true); wrapper.setReadonly(true); + wrapper.initializeContainers(this); + if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { + showResultInSession(wrapper.getResult()); + } return wrapper; @@ -281,14 +283,15 @@ private ObjectWrapper getObjectNewWrapper() { ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper( createStringResource("pageWorkItem.objectNew.description").getString(), // name (large font) PolyString.getOrig(prism.asObjectable().getName()), // description (smaller font) - prism, status, this); - if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { - showResultInSession(wrapper.getResult()); - } + prism, status, true, this); wrapper.setShowEmpty(false); wrapper.setMinimalized(true); wrapper.setShowAssignments(true); wrapper.setReadonly(true); + wrapper.initializeContainers(this); + if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { + showResultInSession(wrapper.getResult()); + } return wrapper; } @@ -310,14 +313,14 @@ private ObjectWrapper getRequestSpecificWrapper() { ContainerStatus status = ContainerStatus.MODIFYING; try{ - ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper("pageWorkItem.requestSpecifics", null, prism, status, this); -// ObjectWrapper wrapper = new ObjectWrapper("pageWorkItem.requestSpecifics", null, prism, status); - if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { - showResultInSession(wrapper.getResult()); - } - wrapper.setShowEmpty(true); - wrapper.setMinimalized(false); - wrapper.setShowInheritedObjectAttributes(false); + ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper("pageWorkItem.requestSpecifics", null, prism, status, true, this); + wrapper.setShowEmpty(true); + wrapper.setMinimalized(false); + wrapper.setShowInheritedObjectAttributes(false); + wrapper.initializeContainers(this); + if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { + showResultInSession(wrapper.getResult()); + } return wrapper; } catch (Exception ex){ @@ -336,22 +339,19 @@ private ObjectWrapper getAdditionalDataWrapper() { } ContainerStatus status = ContainerStatus.MODIFYING; - try{ - ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper( - createStringResource("pageWorkItem.additionalData.description").getString(), // name (large font) - PolyString.getOrig(prism.asObjectable().getName()), // description (smaller font) - prism, status, this); -// ObjectWrapper wrapper = new ObjectWrapper( -// createStringResource("pageWorkItem.additionalData.description").getString(), // name (large font) -// PolyString.getOrig(prism.asObjectable().getName()), // description (smaller font) -// prism, status); - if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { - showResultInSession(wrapper.getResult()); - } - wrapper.setShowEmpty(false); - wrapper.setMinimalized(true); - wrapper.setReadonly(true); - return wrapper; + try { + ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper( + createStringResource("pageWorkItem.additionalData.description").getString(), // name (large font) + PolyString.getOrig(prism.asObjectable().getName()), // description (smaller font) + prism, status, true, this); + wrapper.setShowEmpty(false); + wrapper.setMinimalized(true); + wrapper.setReadonly(true); + wrapper.initializeContainers(this); + if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { + showResultInSession(wrapper.getResult()); + } + return wrapper; } catch (Exception ex){ LoggingUtils.logException(LOGGER, "Couldn't get work item.", ex); } @@ -365,15 +365,15 @@ private ObjectWrapper getTrackingDataWrapper() { ContainerStatus status = ContainerStatus.MODIFYING; try { ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper("pageWorkItem.trackingData", null, - prism, status, this); - // ObjectWrapper wrapper = new - // ObjectWrapper("pageWorkItem.trackingData", null, prism, status); - if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { - showResultInSession(wrapper.getResult()); - } + prism, status, true, this); wrapper.setShowEmpty(false); wrapper.setMinimalized(true); wrapper.setReadonly(true); + wrapper.initializeContainers(this); + wrapper.setShowInheritedObjectAttributes(false); + if (wrapper.getResult() != null && !WebMiscUtil.isSuccessOrHandledError(wrapper.getResult())) { + showResultInSession(wrapper.getResult()); + } return wrapper; } catch (Exception ex) { 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 ef18d439a20..e51cf91d151 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 @@ -31,6 +31,7 @@ import com.evolveum.midpoint.model.api.WorkflowService; import com.evolveum.midpoint.model.api.hooks.ReadHook; import com.evolveum.midpoint.wf.api.WorkflowManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectSpecificationType; import com.evolveum.midpoint.xml.ns._public.model.model_context_3.LensContextType; import org.apache.commons.lang.NotImplementedException; @@ -751,9 +752,13 @@ private D applySecurityContraints(D origItemDefinitio List origSubDefinitions = ((PrismContainerDefinition)origItemDefinition).getDefinitions(); containerDefinition.getDefinitions().clear(); for (ItemDefinition subDef: origSubDefinitions) { - ItemDefinition newDef = applySecurityContraints(subDef, new ItemPath(itemPath, subDef.getName()), securityConstraints, - readDecision, addDecision, modifyDecision); - containerDefinition.getComplexTypeDefinition().add(newDef); + // TODO fix this brutal hack - it is necessary to avoid endless recursion in the style of "Decision for authorization/object/owner/owner/......../owner/special: ALLOW" + // it's too late to come up with a serious solution + if (!(itemPath.lastNamed() != null && ObjectSpecificationType.F_OWNER.equals(itemPath.lastNamed().getName()) && ObjectSpecificationType.F_OWNER.equals(subDef.getName()))) { + ItemDefinition newDef = applySecurityContraints(subDef, new ItemPath(itemPath, subDef.getName()), securityConstraints, + readDecision, addDecision, modifyDecision); + containerDefinition.getComplexTypeDefinition().add(newDef); + } } } return itemDefinition; From e2008c147a1cc75bdd41821fdeedb410b7c3c86f Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Fri, 27 Jun 2014 01:03:13 +0200 Subject: [PATCH 02/12] Fix for displaying associations at user page. --- .../com/evolveum/midpoint/web/page/admin/users/PageUser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 6f6ad6068f0..22b216f9165 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 @@ -643,7 +643,7 @@ private List loadAccountWrappers() { String resourceName = WebMiscUtil.getName(resource); ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper(resourceName, WebMiscUtil.getOrigStringFromPoly(accountType - .getName()), account, ContainerStatus.MODIFYING, this); + .getName()), account, ContainerStatus.MODIFYING, true, this); // ObjectWrapper wrapper = new ObjectWrapper(resourceName, WebMiscUtil.getOrigStringFromPoly(accountType // .getName()), account, ContainerStatus.MODIFYING); wrapper.setFetchResult(OperationResult.createOperationResult(fetchResult)); @@ -664,7 +664,7 @@ private List loadAccountWrappers() { } - + wrapper.initializeContainers(this); list.add(new UserAccountDto(wrapper, UserDtoStatus.MODIFY)); From 6b2153cf7c6c00db28a054387f30d2a50662e777 Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Fri, 27 Jun 2014 12:29:12 +0200 Subject: [PATCH 03/12] Removing unreliable assertion --- .../evolveum/midpoint/model/intest/sync/TestImportRecon.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestImportRecon.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestImportRecon.java index af30f7ec654..bec9123e9a2 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestImportRecon.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/sync/TestImportRecon.java @@ -1235,9 +1235,6 @@ public void test502ImportAugustusFromResourceDummy() throws Exception { // Second fetch: fetchback to correctly process inbound (import changes the account). // assertShadowFetchOperationCountIncrement(2); - // WHY??? - assertShadowFetchOperationCountIncrement(1); - assertImportedUserByOid(USER_ADMINISTRATOR_OID); assertImportedUserByOid(USER_JACK_OID); assertImportedUserByOid(USER_BARBOSSA_OID); From 0f3731dffc36818bd42a7741a524b62e47b20415 Mon Sep 17 00:00:00 2001 From: Erik Suta Date: Fri, 27 Jun 2014 13:43:50 +0200 Subject: [PATCH 04/12] MID-1931 implementation. It is now possible to delete 3 types of shadow, all users and all org. units from one place in debug pages. --- .../web/component/dialog/DeleteAllDialog.html | 94 ++++ .../web/component/dialog/DeleteAllDialog.java | 500 ++++++++++++++++++ .../dialog/DeleteAllDialog.properties | 24 + .../admin/configuration/PageDebugList.html | 1 + .../admin/configuration/PageDebugList.java | 271 ++++++---- .../configuration/PageDebugList.properties | 14 +- .../configuration/dto/DebugConfDialogDto.java | 2 +- 7 files changed, 799 insertions(+), 107 deletions(-) create mode 100644 gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.html create mode 100644 gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.java create mode 100644 gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.properties diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.html new file mode 100644 index 00000000000..d2fdd478956 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.html @@ -0,0 +1,94 @@ + + +
+ +

+ + + +

+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +

+ +

+ +

+ + +

+
+
\ No newline at end of file diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.java new file mode 100644 index 00000000000..3138348f16a --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.java @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2010-2013 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.web.component.dialog; + +import com.evolveum.midpoint.model.api.ModelService; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.ResultHandler; +import com.evolveum.midpoint.schema.SelectorOptions; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.logging.LoggingUtils; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.component.AjaxButton; +import com.evolveum.midpoint.web.component.util.LoadableModel; +import com.evolveum.midpoint.web.page.PageBase; +import com.evolveum.midpoint.web.util.WebModelUtils; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.OnChangeAjaxBehavior; +import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.CheckBox; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.StringResourceModel; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * @author shood + * */ +public class DeleteAllDialog extends ModalWindow{ + + private static final Trace LOGGER = TraceManager.getTrace(DeleteAllDialog.class); + + private static final String DOT_CLASS = DeleteAllDialog.class.getName() + "."; + private static final String OPERATION_SEARCH_ITERATIVE_TASK = DOT_CLASS + "searchIterativeTask"; + private static final String OPERATION_COUNT_TASK = DOT_CLASS + "countObjectsTask"; + + private static final String ID_CHB_USERS = "checkboxUsers"; + private static final String ID_CHB_ORG = "checkboxOrg"; + private static final String ID_CHB_ACCOUNT_SHADOW = "checkboxAccountShadow"; + private static final String ID_CHB_ROLE_SHADOW = "checkboxRoleShadow"; + private static final String ID_CHB_ORG_SHADOW = "checkboxOrgShadow"; + private static final String ID_TEXT_USERS = "confirmTextUsers"; + private static final String ID_TEXT_ORGS = "confirmTextOrgUnits"; + private static final String ID_TEXT_ACC_SHADOWS = "confirmTextAccountShadow"; + private static final String ID_TEXT_ROLE_SHADOWS = "confirmTextRoleShadows"; + private static final String ID_TEXT_ORG_SHADOWS = "confirmTextOrgShadows"; + private static final String ID_YES = "yes"; + private static final String ID_NO = "no"; + private static final String ID_TOTAL = "totalCountLabel"; + private static final String EMPTY_LABEL = ""; + + private static final String ID_FOCUS_TYPE_ORG = "OrgType"; + private static final String ID_FOCUS_TYPE_ROLE = "RoleType"; + + private IModel messageUsers; + private IModel messageOrgUnits; + private IModel messageAccountShadows; + private IModel messageRoleShadows; + private IModel messageOrgShadows; + private IModel messageTotal; + protected IModel deleteUsers = Model.of(Boolean.FALSE); + protected IModel deleteOrgs = Model.of(Boolean.FALSE); + protected IModel deleteAccountShadow = Model.of(Boolean.FALSE); + protected IModel deleteRoleShadow = Model.of(Boolean.FALSE); + protected IModel deleteOrgShadow = Model.of(Boolean.FALSE); + + private int objectsToDelete = 0; + private int accountShadowTypeCount = 0; + private int orgUnitCount = 0; + private int userCount = 0; + private int orgShadowCount = 0; + private int roleShadowCount = 0; + + public DeleteAllDialog(String id, IModel title){ + super(id); + + if(title != null){ + setTitle(title); + } + + loadMessages(); + setCssClassName(ModalWindow.CSS_CLASS_GRAY); + setCookieName(ConfirmationDialog.class.getSimpleName() + ((int) (Math.random() * 100))); + showUnloadConfirmation(false); + setResizable(false); + setInitialWidth(550); + setInitialHeight(350); + setWidthUnit("px"); + + setCloseButtonCallback(new ModalWindow.CloseButtonCallback() { + + @Override + public boolean onCloseButtonClicked(AjaxRequestTarget target) { + return true; + } + }); + + setWindowClosedCallback(new ModalWindow.WindowClosedCallback() { + + @Override + public void onClose(AjaxRequestTarget target) { + DeleteAllDialog.this.close(target); + } + }); + + WebMarkupContainer content = new WebMarkupContainer(getContentId()); + setContent(content); + + initLayout(content); + } + + private void loadMessages(){ + messageUsers = new LoadableModel() { + @Override + protected String load() { + return createDeleteUsersMessage(); + } + }; + + messageOrgUnits = new LoadableModel() { + @Override + protected String load() { + return createDeleteOrgUnitsMessage(); + } + }; + + messageAccountShadows = new LoadableModel() { + @Override + protected String load() { + return createDeleteAccountShadowsMessage(); + } + }; + + messageOrgShadows = new LoadableModel() { + @Override + protected String load() { + return createDeleteShadowsMessage(ID_FOCUS_TYPE_ORG); + } + }; + + messageRoleShadows = new LoadableModel() { + @Override + protected String load() { + return createDeleteShadowsMessage(ID_FOCUS_TYPE_ROLE); + } + }; + + messageTotal = new LoadableModel() { + + @Override + protected String load() { + return createTotalMessage(); + } + }; + } + + private void initLayout(WebMarkupContainer content){ + + CheckBox deleteUsersCheckbox = new CheckBox(ID_CHB_USERS, deleteUsers); + deleteUsersCheckbox.add(new OnChangeAjaxBehavior() { + + @Override + protected void onUpdate(AjaxRequestTarget target) { + messageUsers.setObject(createDeleteUsersMessage()); + messageTotal.setObject(createTotalMessage()); + target.add(getLabel(ID_TEXT_USERS)); + target.add(getLabel(ID_TOTAL)); + } + }); + content.add(deleteUsersCheckbox); + + CheckBox deleteOrgsCheckbox = new CheckBox(ID_CHB_ORG, deleteOrgs); + deleteOrgsCheckbox.add(new OnChangeAjaxBehavior() { + + @Override + protected void onUpdate(AjaxRequestTarget target) { + messageOrgUnits.setObject(createDeleteOrgUnitsMessage()); + messageTotal.setObject(createTotalMessage()); + target.add(getLabel(ID_TEXT_ORGS)); + target.add(getLabel(ID_TOTAL)); + } + }); + content.add(deleteOrgsCheckbox); + + CheckBox deleteAccountShadowsCheckbox = new CheckBox(ID_CHB_ACCOUNT_SHADOW, deleteAccountShadow); + deleteAccountShadowsCheckbox.add(new OnChangeAjaxBehavior() { + + @Override + protected void onUpdate(AjaxRequestTarget target) { + messageAccountShadows.setObject(createDeleteAccountShadowsMessage()); + messageTotal.setObject(createTotalMessage()); + target.add(getLabel(ID_TEXT_ACC_SHADOWS)); + target.add(getLabel(ID_TOTAL)); + } + }); + content.add(deleteAccountShadowsCheckbox); + + CheckBox deleteOrgShadowsCheckbox = new CheckBox(ID_CHB_ORG_SHADOW, deleteOrgShadow); + deleteOrgShadowsCheckbox.add(new OnChangeAjaxBehavior() { + + @Override + protected void onUpdate(AjaxRequestTarget target) { + messageOrgShadows.setObject(createDeleteShadowsMessage(ID_FOCUS_TYPE_ORG)); + messageTotal.setObject(createTotalMessage()); + target.add(getLabel(ID_TEXT_ORG_SHADOWS)); + target.add(getLabel(ID_TOTAL)); + } + }); + content.add(deleteOrgShadowsCheckbox); + + CheckBox deleteRoleShadowsCheckbox = new CheckBox(ID_CHB_ROLE_SHADOW, deleteRoleShadow); + deleteRoleShadowsCheckbox.add(new OnChangeAjaxBehavior() { + + @Override + protected void onUpdate(AjaxRequestTarget target) { + messageRoleShadows.setObject(createDeleteShadowsMessage(ID_FOCUS_TYPE_ROLE)); + messageTotal.setObject(createTotalMessage()); + target.add(getLabel(ID_TEXT_ROLE_SHADOWS)); + target.add(getLabel(ID_TOTAL)); + } + }); + content.add(deleteRoleShadowsCheckbox); + + Label usersLabel = new Label(ID_TEXT_USERS, messageUsers); + usersLabel.setOutputMarkupId(true); + content.add(usersLabel); + + Label orgsLabel = new Label(ID_TEXT_ORGS, messageOrgUnits); + orgsLabel.setOutputMarkupId(true); + content.add(orgsLabel); + + Label accShadowsLabel = new Label(ID_TEXT_ACC_SHADOWS, messageAccountShadows); + accShadowsLabel.setOutputMarkupId(true); + content.add(accShadowsLabel); + + Label orgShadowsLabel = new Label(ID_TEXT_ORG_SHADOWS, messageOrgShadows); + orgShadowsLabel.setOutputMarkupId(true); + content.add(orgShadowsLabel); + + Label roleShadowsLabel = new Label(ID_TEXT_ROLE_SHADOWS, messageRoleShadows); + roleShadowsLabel.setOutputMarkupId(true); + content.add(roleShadowsLabel); + + Label countLabel = new Label(ID_TOTAL, messageTotal); + countLabel.setOutputMarkupId(true); + content.add(countLabel); + + AjaxButton yesButton = new AjaxButton(ID_YES, new StringResourceModel("deleteAllDialog.yes", + this, null)) { + + @Override + public void onClick(AjaxRequestTarget target) { + yesPerformed(target); + } + }; + content.add(yesButton); + + AjaxButton noButton = new AjaxButton(ID_NO, new StringResourceModel("deleteAllDialog.no", + this, null)) { + + @Override + public void onClick(AjaxRequestTarget target) { + noPerformed(target); + } + }; + content.add(noButton); + } + + private Label getLabel(String ID){ + return (Label)get(getContentId()+":"+ID); + } + + public StringResourceModel createStringResource(String resourceKey, Object... objects) { + return new StringResourceModel(resourceKey, this, new Model(), resourceKey, objects); + } + + private String createTotalMessage(){ + objectsToDelete = 0; + if(deleteUsers.getObject()){ + objectsToDelete += userCount; + } + if(deleteOrgs.getObject()){ + objectsToDelete += orgUnitCount; + } + if(deleteAccountShadow.getObject()){ + objectsToDelete += accountShadowTypeCount; + } + if(deleteOrgShadow.getObject()){ + objectsToDelete += orgShadowCount; + } + if(deleteRoleShadow.getObject()){ + objectsToDelete += roleShadowCount; + } + + return createStringResource("pageDebugList.label.totalToDelete", objectsToDelete).getString(); + } + + private String createDeleteUsersMessage(){ + if(!deleteUsers.getObject()){ + return createStringResource("pageDebugList.label.usersDelete", 0).getString(); + } + + userCount = 0; + + Task task = createSimpleTask(OPERATION_COUNT_TASK); + OperationResult result = new OperationResult(OPERATION_COUNT_TASK); + + Collection> options = new ArrayList>(); + GetOperationOptions opt = GetOperationOptions.createRaw(); + options.add(SelectorOptions.create(ItemPath.EMPTY_PATH, opt)); + + try { + userCount = getModelService().countObjects(UserType.class, null, options, task, result); + + //We need to substract 1, because we are not deleting user 'Administrator' + userCount--; + objectsToDelete += userCount; + } catch (Exception ex) { + result.computeStatus(getString("pageDebugList.message.countSearchProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.countSearchProblem"), ex); + } + + return createStringResource("pageDebugList.label.usersDelete", userCount).getString(); + } + + private String createDeleteOrgUnitsMessage(){ + if(!deleteOrgs.getObject()){ + return createStringResource("pageDebugList.label.orgUnitsDelete", 0).getString(); + } + + orgUnitCount = 0; + + Task task = createSimpleTask(OPERATION_COUNT_TASK); + OperationResult result = new OperationResult(OPERATION_COUNT_TASK); + + Collection> options = new ArrayList>(); + GetOperationOptions opt = GetOperationOptions.createRaw(); + options.add(SelectorOptions.create(ItemPath.EMPTY_PATH, opt)); + + try { + orgUnitCount = getModelService().countObjects(OrgType.class, null, options, task, result); + + objectsToDelete += orgUnitCount; + } catch (Exception ex) { + result.computeStatus(getString("pageDebugList.message.countSearchProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.countSearchProblem"), ex); + } + + return createStringResource("pageDebugList.label.orgUnitsDelete", orgUnitCount).getString(); + } + + private String createDeleteAccountShadowsMessage(){ + if(!deleteAccountShadow.getObject()){ + return createStringResource("pageDebugList.label.accountShadowsDelete", 0).getString(); + } + + accountShadowTypeCount = 0; + + Task task = createSimpleTask(OPERATION_SEARCH_ITERATIVE_TASK); + OperationResult result = new OperationResult(OPERATION_SEARCH_ITERATIVE_TASK); + + Collection> options = new ArrayList>(); + GetOperationOptions opt = GetOperationOptions.createRaw(); + options.add(SelectorOptions.create(ItemPath.EMPTY_PATH, opt)); + + ResultHandler accountShadowHandler = new ResultHandler() { + @Override + public boolean handle(PrismObject object, OperationResult parentResult) { + ShadowType shadow = (ShadowType)object.asObjectable(); + if(ShadowKindType.ACCOUNT.equals(shadow.getKind())){ + accountShadowTypeCount++; + } + return true; + } + }; + + try { + getModelService().searchObjectsIterative(ShadowType.class, null, accountShadowHandler, options, task, result); + objectsToDelete += accountShadowTypeCount; + } catch (Exception ex) { + result.computeStatus(getString("pageDebugList.message.countSearchProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.countSearchProblem"), ex); + } + + return createStringResource("pageDebugList.label.accountShadowsDelete", accountShadowTypeCount).getString(); + } + + private String createDeleteShadowsMessage(final String focus){ + if(ID_FOCUS_TYPE_ORG.equals(focus) && !deleteOrgShadow.getObject()){ + return createStringResource("pageDebugList.label.orgShadowsDelete", 0).getString(); + } else if(ID_FOCUS_TYPE_ROLE.equals(focus) && !deleteRoleShadow.getObject()){ + return createStringResource("pageDebugList.label.roleShadowsDelete", 0).getString(); + } + + orgShadowCount = 0; + roleShadowCount = 0; + int count = 0; + + Task task = createSimpleTask(OPERATION_SEARCH_ITERATIVE_TASK); + final OperationResult result = new OperationResult(OPERATION_SEARCH_ITERATIVE_TASK); + + Collection> options = new ArrayList>(); + GetOperationOptions opt = GetOperationOptions.createRaw(); + options.add(SelectorOptions.create(ItemPath.EMPTY_PATH, opt)); + + ResultHandler orgShadowHandler = new ResultHandler() { + @Override + public boolean handle(PrismObject object, OperationResult parentResult) { + ShadowType shadow = (ShadowType)object.asObjectable(); + if(!ShadowKindType.ACCOUNT.equals(shadow.getKind())){ + String oid = shadow.getResourceRef().getOid(); + + PrismObject resource = WebModelUtils.loadObject(ResourceType.class, oid, result, (PageBase) getPage()); + + if(resource != null && resource.asObjectable() != null){ + SynchronizationType sync = resource.asObjectable().getSynchronization(); + + for(ObjectSynchronizationType s: sync.getObjectSynchronization()){ + if(s.getFocusType() != null && focus.equals(s.getFocusType().getLocalPart())){ + addShadowType(focus); + } + } + } + } + return true; + } + }; + + try { + getModelService().searchObjectsIterative(ShadowType.class, null, orgShadowHandler, options, task, result); + if(ID_FOCUS_TYPE_ORG.equals(focus)){ + count = orgShadowCount; + } else if(ID_FOCUS_TYPE_ROLE.equals(focus)){ + count = roleShadowCount; + } + + objectsToDelete += count; + } catch (Exception ex) { + result.computeStatus(getString("pageDebugList.message.countSearchProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.countSearchProblem"), ex); + } + + if(ID_FOCUS_TYPE_ORG.equals(focus)){ + return createStringResource("pageDebugList.label.orgShadowsDelete", count).getString(); + } else if(ID_FOCUS_TYPE_ROLE.equals(focus)){ + return createStringResource("pageDebugList.label.roleShadowsDelete", count).getString(); + } else { + return EMPTY_LABEL; + } + } + + public int getObjectsToDelete(){ + return objectsToDelete; + } + + private void addShadowType(String focus){ + if(ID_FOCUS_TYPE_ORG.equals(focus)){ + orgShadowCount++; + } else if(ID_FOCUS_TYPE_ROLE.equals(focus)){ + roleShadowCount++; + } + } + + public Task createSimpleTask(String operation){ + return null; + } + + public ModelService getModelService(){ + return null; + } + + public void yesPerformed(AjaxRequestTarget target) { + + } + + public void noPerformed(AjaxRequestTarget target) { + close(target); + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.properties new file mode 100644 index 00000000000..ec56d3c3ad8 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +deleteAllDialog.yes=Yes +deleteAllDialog.no=No +deleteAllDialog.message.choose=Choose object types to delete: +deleteAllDialog.label.users=Users +deleteAllDialog.label.org=Org. Units +deleteAllDialog.label.shadow.account=Account shadows +deleteAllDialog.label.shadow.role=Role shadows +deleteAllDialog.label.shadow.org=Org. unit shadows diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.html index a6b7ae0d70d..aadb03c9c36 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.html @@ -19,6 +19,7 @@
+
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.java index 83c335711d9..571f369bd72 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.java @@ -17,6 +17,7 @@ package com.evolveum.midpoint.web.page.admin.configuration; import com.evolveum.midpoint.model.api.ModelExecuteOptions; +import com.evolveum.midpoint.model.api.ModelService; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.match.PolyStringNormMatchingRule; @@ -46,8 +47,10 @@ import com.evolveum.midpoint.web.component.data.column.InlineMenuable; import com.evolveum.midpoint.web.component.data.column.LinkColumn; import com.evolveum.midpoint.web.component.dialog.ConfirmationDialog; +import com.evolveum.midpoint.web.component.dialog.DeleteAllDialog; import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; import com.evolveum.midpoint.web.component.util.LoadableModel; +import com.evolveum.midpoint.web.page.PageBase; import com.evolveum.midpoint.web.page.admin.configuration.component.DebugButtonPanel; import com.evolveum.midpoint.web.page.admin.configuration.component.HeaderMenuAction; import com.evolveum.midpoint.web.page.admin.configuration.component.PageDebugDownloadBehaviour; @@ -58,10 +61,7 @@ import com.evolveum.midpoint.web.util.ObjectTypeGuiDescriptor; import com.evolveum.midpoint.web.util.WebMiscUtil; import com.evolveum.midpoint.web.util.WebModelUtils; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemObjectsType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang.StringUtils; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -97,7 +97,6 @@ public class PageDebugList extends PageAdminConfiguration { private static final String DOT_CLASS = PageDebugList.class.getName() + "."; private static final String OPERATION_DELETE_OBJECTS = DOT_CLASS + "deleteObjects"; - private static final String OPERATION_SEARCH_ITERATIVE_TASK = DOT_CLASS + "searchIterativeTask"; private static final String OPERATION_LAXATIVE_DELETE = DOT_CLASS + "laxativeDelete"; private static final String ID_CONFIRM_DELETE_POPUP = "confirmDeletePopup"; @@ -109,20 +108,18 @@ public class PageDebugList extends PageAdminConfiguration { private static final String ID_EXPORT_ALL = "exportAll"; private static final String ID_SEARCH_FORM = "searchForm"; private static final String ID_BASIC_SEARCH = "basicSearch"; + private static final String ID_DELETE_ALL_DIALOG = "confirmDeleteAll"; + + private static final String ID_FOCUS_TYPE_ORG = "OrgType"; + private static final String ID_FOCUS_TYPE_ROLE = "RoleType"; - private static final String PRINT_LABEL_USER = "User "; - private static final String PRINT_LABEL_SHADOW = "Shadow "; - private static final String PRINT_LABEL_USER_DELETE = "Users to delete: "; - private static final String PRINT_LABEL_SHADOW_DELETE = "Shadows to delete: "; private static final String PRINT_LABEL_HTML_NEWLINE = "
"; - private static final String PRINT_LABEL_ADMINISTRATOR_NOT_DELETED = "(User 'Administrator' will not be deleted)"; // search form model; private IModel searchModel; // confirmation dialog model private IModel confDialogModel = new Model(); - private int objectsToDelete = 0; private int objectsDeleted = 0; public PageDebugList() { @@ -139,7 +136,58 @@ protected DebugSearchDto load() { } private void initLayout() { - //confirm delete + DeleteAllDialog deleteAllDialog = new DeleteAllDialog(ID_DELETE_ALL_DIALOG, + createStringResource("pageDebugList.dialog.title.deleteAll")){ + + @Override + public Task createSimpleTask(String operation){ + return PageDebugList.this.createSimpleTask(operation); + } + + @Override + public ModelService getModelService(){ + return PageDebugList.this.getModelService(); + } + + @Override + public void yesPerformed(AjaxRequestTarget target) { + close(target); + + Collection> options = new ArrayList>(); + GetOperationOptions opt = GetOperationOptions.createRaw(); + options.add(SelectorOptions.create(ItemPath.EMPTY_PATH, opt)); + + Task task = createSimpleTask(OPERATION_LAXATIVE_DELETE); + OperationResult result = new OperationResult(OPERATION_LAXATIVE_DELETE); + + objectsDeleted = 0; + if(deleteUsers.getObject()){ + deleteAllUsers(task, result, options); + } + if(deleteOrgs.getObject()){ + deleteAllOrgUnits(task, result, options); + } + if(deleteAccountShadow.getObject()){ + deleteAllAccountShadows(task, result, options); + } + if(deleteOrgShadow.getObject()){ + deleteAllNonAccountShadows(task, result, options, ID_FOCUS_TYPE_ORG); + } + if(deleteRoleShadow.getObject()){ + deleteAllNonAccountShadows(task, result, options, ID_FOCUS_TYPE_ROLE); + } + + LOGGER.info("Deleted {} out of {} objects.", objectsDeleted, getObjectsToDelete()); + + target.add(getListTable()); + target.add(getFeedbackPanel()); + + result.recomputeStatus(); + showResult(result); + } + }; + add(deleteAllDialog); + ConfirmationDialog deleteConfirm = new ConfirmationDialog(ID_CONFIRM_DELETE_POPUP, createStringResource("pageDebugList.dialog.title.confirmDelete"), createDeleteConfirmString()) { @@ -149,9 +197,6 @@ public void yesPerformed(AjaxRequestTarget target) { DebugConfDialogDto dto = confDialogModel.getObject(); switch (dto.getOperation()) { - case DELETE_ALL_IDENTITIES: - deleteAllIdentitiesConfirmed(target); - break; case DELETE_ALL_TYPE: deleteAllTypeConfirmed(target); break; @@ -483,8 +528,6 @@ public String getObject() { DebugConfDialogDto dto = confDialogModel.getObject(); switch (dto.getOperation()) { - case DELETE_ALL_IDENTITIES: - return createLaxativeString(); case DELETE_ALL_TYPE: String key = ObjectTypeGuiDescriptor.getDescriptor(dto.getType()).getLocalizationKey(); String type = createStringResource(key).getString(); @@ -507,80 +550,85 @@ public String getObject() { }; } - private String createLaxativeString() { - int userCount = 0; - int shadowCount = 0; - final StringBuilder sb = new StringBuilder(); - sb.append(createStringResource("pageDebugList.dialog.title.confirmLaxativeMessage").getString() + "

"); - - Task task = createSimpleTask(OPERATION_SEARCH_ITERATIVE_TASK); - OperationResult result = new OperationResult(OPERATION_SEARCH_ITERATIVE_TASK); - - Collection> options = new ArrayList>(); - GetOperationOptions opt = GetOperationOptions.createRaw(); - options.add(SelectorOptions.create(ItemPath.EMPTY_PATH, opt)); - + private void deleteAllUsers(Task task, OperationResult result, Collection> options){ ResultHandler userHandler = new ResultHandler() { + @Override public boolean handle(PrismObject object, OperationResult parentResult) { if (!SystemObjectsType.USER_ADMINISTRATOR.value().equals(object.asObjectable().getOid())) { - sb.append(PRINT_LABEL_USER).append(WebMiscUtil.getName(object)).append(PRINT_LABEL_HTML_NEWLINE); + ObjectDelta delta = ObjectDelta.createDeleteDelta(UserType.class, object.asObjectable().getOid(), getPrismContext()); + Task task = createSimpleTask(OPERATION_LAXATIVE_DELETE); + OperationResult r = new OperationResult(OPERATION_LAXATIVE_DELETE); + + try { + getModelService().executeChanges(WebMiscUtil.createDeltaCollection(delta), ModelExecuteOptions.createRaw(), task, r); + objectsDeleted++; + + if (objectsDeleted % 10 == 0) + LOGGER.info("Deleted {} out of {} objects.", objectsDeleted, getObjectsToDelete()); + + r.recordSuccess(); + } catch (Exception ex) { + r.computeStatus(getString("pageDebugList.message.singleUserDeleteProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.singleUserDeleteProblem"), ex); + } + parentResult.addSubresult(r); } return true; } }; - ResultHandler shadowHandler = new ResultHandler() { + try { + getModelService().searchObjectsIterative(UserType.class, null, userHandler, options, task, result); + } catch (Exception ex) { + result.computeStatus(getString("pageDebugList.message.laxativeProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.laxativeProblem"), ex); + } + } + + private void deleteAllOrgUnits(Task task, OperationResult result, Collection> options){ + ResultHandler userHandler = new ResultHandler() { + @Override public boolean handle(PrismObject object, OperationResult parentResult) { - sb.append(PRINT_LABEL_SHADOW).append(WebMiscUtil.getName(object)).append(PRINT_LABEL_HTML_NEWLINE); - return true; - } - }; - - try { - userCount = getModelService().countObjects(UserType.class, null, options, task, result); + ObjectDelta delta = ObjectDelta.createDeleteDelta(OrgType.class, object.asObjectable().getOid(), getPrismContext()); + Task task = createSimpleTask(OPERATION_LAXATIVE_DELETE); + OperationResult r = new OperationResult(OPERATION_LAXATIVE_DELETE); - //We need to substract 1, because we are not deleting user 'Administrator' - userCount--; + try { + getModelService().executeChanges(WebMiscUtil.createDeltaCollection(delta), ModelExecuteOptions.createRaw(), task, r); + objectsDeleted++; - shadowCount = getModelService().countObjects(ShadowType.class, null, options, task, result); + if (objectsDeleted % 10 == 0) + LOGGER.info("Deleted {} out of {} objects.", objectsDeleted, getObjectsToDelete()); - objectsToDelete = userCount + shadowCount; + r.recordSuccess(); + } catch (Exception ex) { + r.computeStatus(getString("pageDebugList.message.singleOrgDeleteProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.singleOrgDeleteProblem"), ex); + } + parentResult.addSubresult(r); - if (userCount >= 10 || shadowCount >= 10) { - sb.append(PRINT_LABEL_USER_DELETE).append(userCount).append(PRINT_LABEL_HTML_NEWLINE).append(PRINT_LABEL_SHADOW_DELETE).append(shadowCount).append(PRINT_LABEL_HTML_NEWLINE); - sb.append(PRINT_LABEL_ADMINISTRATOR_NOT_DELETED).append(PRINT_LABEL_HTML_NEWLINE); - } else { - sb.append(PRINT_LABEL_USER_DELETE).append(userCount).append(PRINT_LABEL_HTML_NEWLINE); - sb.append(PRINT_LABEL_ADMINISTRATOR_NOT_DELETED).append(PRINT_LABEL_HTML_NEWLINE); - getModelService().searchObjectsIterative(UserType.class, null, userHandler, options, task, result); - sb.append(PRINT_LABEL_HTML_NEWLINE); - sb.append(PRINT_LABEL_SHADOW_DELETE).append(shadowCount).append(PRINT_LABEL_HTML_NEWLINE); - getModelService().searchObjectsIterative(ShadowType.class, null, shadowHandler, options, task, result); + return true; } + }; + + try { + getModelService().searchObjectsIterative(OrgType.class, null, userHandler, options, task, result); } catch (Exception ex) { - result.computeStatus(getString("pageDebugList.message.countSearchProblem")); - LoggingUtils.logException(LOGGER, getString("pageDebugList.message.countSearchProblem"), ex); + result.computeStatus(getString("pageDebugList.message.laxativeProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.laxativeProblem"), ex); } - - return sb.toString(); } - private void deleteAllIdentities() { - Collection> options = new ArrayList>(); - GetOperationOptions opt = GetOperationOptions.createRaw(); - options.add(SelectorOptions.create(ItemPath.EMPTY_PATH, opt)); - - Task laxativeTask = createSimpleTask(OPERATION_LAXATIVE_DELETE); - OperationResult result = new OperationResult(OPERATION_LAXATIVE_DELETE); - - ResultHandler userHandler = new ResultHandler() { + private void deleteAllAccountShadows(Task task, OperationResult result, Collection> options){ + ResultHandler shadowHandler = new ResultHandler() { @Override public boolean handle(PrismObject object, OperationResult parentResult) { - if (!SystemObjectsType.USER_ADMINISTRATOR.value().equals(object.asObjectable().getOid())) { - ObjectDelta delta = ObjectDelta.createDeleteDelta(UserType.class, object.asObjectable().getOid(), getPrismContext()); + ShadowType shadow = (ShadowType)object.asObjectable(); + if(ShadowKindType.ACCOUNT.equals(shadow.getKind())){ + ObjectDelta delta = ObjectDelta.createDeleteDelta(ShadowType.class, object.asObjectable().getOid(), getPrismContext()); Task task = createSimpleTask(OPERATION_LAXATIVE_DELETE); OperationResult r = new OperationResult(OPERATION_LAXATIVE_DELETE); @@ -588,55 +636,83 @@ public boolean handle(PrismObject object, OperationResult parentResult) { getModelService().executeChanges(WebMiscUtil.createDeltaCollection(delta), ModelExecuteOptions.createRaw(), task, r); objectsDeleted++; - if (objectsDeleted % 100 == 0) - LOGGER.info("Deleted {} out of {} objects.", objectsDeleted, objectsToDelete); + if (objectsDeleted % 10 == 0) + LOGGER.info("Deleted {} out of {} objects.", objectsDeleted, getObjectsToDelete()); r.recordSuccess(); } catch (Exception ex) { - r.computeStatus(getString("pageDebugList.message.singleDeleteProblemUser")); - LoggingUtils.logException(LOGGER, getString("pageDebugList.message.singleDeleteProblemUser"), ex); + r.computeStatus(getString("pageDebugList.message.singleShadowDeleteProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.singleShadowDeleteProblem"), ex); } parentResult.addSubresult(r); } + return true; } - }; + try { + getModelService().searchObjectsIterative(ShadowType.class, null, shadowHandler, options, task, result); + } catch (Exception ex) { + result.computeStatus(getString("pageDebugList.message.laxativeProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.laxativeProblem"), ex); + } + } + + private void deleteAllNonAccountShadows(Task task, final OperationResult result, Collection> options, + final String focus){ ResultHandler shadowHandler = new ResultHandler() { + @Override public boolean handle(PrismObject object, OperationResult parentResult) { - ObjectDelta delta = ObjectDelta.createDeleteDelta(ShadowType.class, object.asObjectable().getOid(), getPrismContext()); - Task task = createSimpleTask(OPERATION_LAXATIVE_DELETE); - OperationResult r = new OperationResult(OPERATION_LAXATIVE_DELETE); + ShadowType shadow = (ShadowType)object.asObjectable(); - try { - getModelService().executeChanges(WebMiscUtil.createDeltaCollection(delta), ModelExecuteOptions.createRaw(), task, r); - objectsDeleted++; + if(!ShadowKindType.ACCOUNT.equals(shadow.getKind())){ + ObjectDelta delta = ObjectDelta.createDeleteDelta(ShadowType.class, object.asObjectable().getOid(), getPrismContext()); + Task task = createSimpleTask(OPERATION_LAXATIVE_DELETE); + OperationResult r = new OperationResult(OPERATION_LAXATIVE_DELETE); + String oid = shadow.getResourceRef().getOid(); - if (objectsDeleted % 100 == 0) - LOGGER.info("Deleted {} out of {} objects.", objectsDeleted, objectsToDelete); + PrismObject resource = WebModelUtils.loadObject(ResourceType.class, oid, result, (PageBase)getPage()); - r.recordSuccess(); - } catch (Exception ex) { - r.computeStatus(getString("pageDebugList.message.singleDeleteProblemShadow")); - LoggingUtils.logException(LOGGER, getString("pageDebugList.message.singleDeleteProblemShadow"), ex); + if(resource != null && resource.asObjectable() != null){ + SynchronizationType sync = resource.asObjectable().getSynchronization(); + + for(ObjectSynchronizationType s: sync.getObjectSynchronization()){ + if(s.getFocusType() != null && focus.equals(s.getFocusType().getLocalPart())){ + try { + getModelService().executeChanges(WebMiscUtil.createDeltaCollection(delta), ModelExecuteOptions.createRaw(), task, r); + objectsDeleted++; + + if (objectsDeleted % 10 == 0) + LOGGER.info("Deleted {} out of {} objects.", objectsDeleted, getObjectsToDelete()); + + r.recordSuccess(); + } catch (Exception ex) { + r.computeStatus(getString("pageDebugList.message.singleShadowDeleteProblem")); + LoggingUtils.logException(LOGGER, getString("pageDebugList.message.singleShadowDeleteProblem"), ex); + } + parentResult.addSubresult(r); + } + } + } } - parentResult.addSubresult(r); + return true; } }; try { - getModelService().searchObjectsIterative(UserType.class, null, userHandler, options, laxativeTask, result); - getModelService().searchObjectsIterative(ShadowType.class, null, shadowHandler, options, laxativeTask, result); + getModelService().searchObjectsIterative(ShadowType.class, null, shadowHandler, options, task, result); } catch (Exception ex) { result.computeStatus(getString("pageDebugList.message.laxativeProblem")); LoggingUtils.logException(LOGGER, getString("pageDebugList.message.laxativeProblem"), ex); } + } - result.recomputeStatus(); - showResult(result); + private int getObjectsToDelete(){ + DeleteAllDialog dialog = (DeleteAllDialog)get(ID_DELETE_ALL_DIALOG); + return dialog.getObjectsToDelete(); } private void exportSelected(AjaxRequestTarget target, DebugObjectItem item) { @@ -708,10 +784,8 @@ private void deleteSelected(AjaxRequestTarget target, DebugObjectItem item) { } private void deleteAllIdentities(AjaxRequestTarget target) { - DebugConfDialogDto dto = new DebugConfDialogDto(DebugConfDialogDto.Operation.DELETE_ALL_IDENTITIES, null, null); - confDialogModel.setObject(dto); - - ModalWindow dialog = (ModalWindow) get(ID_CONFIRM_DELETE_POPUP); + DeleteAllDialog dialog = (DeleteAllDialog) get(ID_DELETE_ALL_DIALOG); +// dialog.getModel().setObject(dialog.createMessage()); dialog.show(target); } @@ -738,15 +812,6 @@ private void deleteSelectedConfirmed(AjaxRequestTarget target, List Date: Fri, 27 Jun 2014 15:33:11 +0200 Subject: [PATCH 05/12] Delete All IDentities popup css fix --- .../midpoint/web/component/dialog/DeleteAllDialog.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.html index d2fdd478956..98f42fe4f05 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/dialog/DeleteAllDialog.html @@ -22,7 +22,7 @@

-
+
@@ -34,7 +34,7 @@
-
+
@@ -46,7 +46,7 @@
-
+
@@ -58,7 +58,7 @@
-
+
@@ -70,7 +70,7 @@
-
+
From c042868659199e54f7f457b5c931aacb056df445 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Fri, 27 Jun 2014 15:53:22 +0200 Subject: [PATCH 06/12] Fix for MID-1957 (moving users between OUs and groups at once). --- .../impl/EntitlementConverter.java | 19 ++++--- .../impl/ResourceObjectConverter.java | 49 ++++++++++++------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/EntitlementConverter.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/EntitlementConverter.java index 4d1d6be7087..bdbf3a8a05f 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/EntitlementConverter.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/EntitlementConverter.java @@ -63,7 +63,6 @@ import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectAssociationDirectionType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectAssociationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAssociationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; @@ -275,7 +274,7 @@ public void processEntitlementsAdd(ResourceType resource, PrismObject void collectEntitlementsAsObjectOperation(Map> roMap, + public void collectEntitlementsAsObjectOperationInShadowAdd(Map> roMap, RefinedObjectClassDefinition objectClassDefinition, PrismObject shadow, RefinedResourceSchema rSchema, ResourceType resource) throws SchemaException { @@ -312,14 +311,14 @@ public void collectEntitlementChange(ContainerDelta itemD public void collectEntitlementsAsObjectOperation(Map> roMap, ContainerDelta containerDelta, RefinedObjectClassDefinition objectClassDefinition, - PrismObject shadow, RefinedResourceSchema rSchema, ResourceType resource) + PrismObject shadowWhenRemovingEntitlements, PrismObject shadowWhenNotRemovingEntitlements, RefinedResourceSchema rSchema, ResourceType resource) throws SchemaException { collectEntitlementsAsObjectOperation(roMap, containerDelta.getValuesToAdd(), objectClassDefinition, - shadow, rSchema, resource, ModificationType.ADD); + shadowWhenNotRemovingEntitlements, rSchema, resource, ModificationType.ADD); collectEntitlementsAsObjectOperation(roMap, containerDelta.getValuesToDelete(), objectClassDefinition, - shadow, rSchema, resource, ModificationType.DELETE); + shadowWhenRemovingEntitlements, rSchema, resource, ModificationType.DELETE); collectEntitlementsAsObjectOperation(roMap, containerDelta.getValuesToReplace(), objectClassDefinition, - shadow, rSchema, resource, ModificationType.REPLACE); + shadowWhenNotRemovingEntitlements, rSchema, resource, ModificationType.REPLACE); } ///////// @@ -520,7 +519,7 @@ private void collectEntitlementToAttrDelta(Map> delt private void collectEntitlementsAsObjectOperation(Map> roMap, Collection> set, RefinedObjectClassDefinition objectClassDefinition, - PrismObject shadow, RefinedResourceSchema rSchema, ResourceType resource, ModificationType modificationType) + PrismObject shadow, RefinedResourceSchema rSchema, ResourceType resource, ModificationType modificationType) throws SchemaException { if (set == null) { return; @@ -533,7 +532,7 @@ private void collectEntitlementsAsObjectOperation(Map void collectEntitlementAsObjectOperation(Map> roMap, PrismContainerValue associationCVal, RefinedObjectClassDefinition objectClassDefinition, - PrismObject shadow, RefinedResourceSchema rSchema, ResourceType resource, ModificationType modificationType) + PrismObject shadow, RefinedResourceSchema rSchema, ResourceType resource, ModificationType modificationType) throws SchemaException { ShadowAssociationType associationType = associationCVal.asContainerable(); @@ -584,14 +583,14 @@ private void collectEntitlementAsObjectOperation(Map valueAttr = ShadowUtil.getAttribute(shadow, valueAttrName); if (valueAttr == null) { // TODO: check schema and try to fetch full shadow if necessary throw new SchemaException("No value attribute "+valueAttrName+" in shadow"); } - + PropertyDelta attributeDelta = null; for(Operation operation: operations) { if (operation instanceof PropertyModificationOperation) { 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 e2110829241..cfd74ea5d68 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 @@ -87,24 +87,15 @@ import com.evolveum.midpoint.util.logging.TraceManager; 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.AttributeFetchStrategyType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AvailabilityStatusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionReturnMultiplicityType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationProvisioningScriptType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationProvisioningScriptsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ProvisioningOperationTypeType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ProvisioningScriptArgumentType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ProvisioningScriptHostType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectAssociationDirectionType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectAssociationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAssociationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAttributesType; 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.resource.capabilities_3.ActivationCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationStatusCapabilityType; -import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType; /** * @@ -404,7 +395,17 @@ public Collection modifyResourceObject( return null; } } - + + /* + * State of the shadow before execution of the deltas - e.g. with original attributes, as it may be recorded in such a way in + * groups of which this account is a member of. (In case of object->subject associations.) + * + * Note: currently this is more-or-less hypothetical situation, because e.g. in AD the subject (account) + * is recorded in object (group) under his current DN -> the one that is in shadowAfter (below). + * So this is currently commented out. + */ + //PrismObject shadowBefore = shadow.clone(); + collectAttributeAndEntitlementChanges(itemDeltas, operations, resource, shadow, objectClassDefinition); Collection sideEffectChanges = null; @@ -426,9 +427,19 @@ public Collection modifyResourceObject( // Execute primary ICF operation on this shadow sideEffectChanges = executeModify(connector, resource, objectClassDefinition, identifiers, operations, parentResult); } - - // Execute entitlement modification on other objects (if needed) - executeEntitlementChangesModify(connector, resource, objectClassDefinition, shadow, scripts, itemDeltas, parentResult); + + /* + * State of the shadow after execution of the deltas - e.g. with new DN (if it was part of the delta), because this one should be recorded + * in groups of which this account is a member of. (In case of object->subject associations.) + */ + PrismObject shadowAfter = shadow.clone(); + for (ItemDelta itemDelta : itemDeltas) { + itemDelta.applyTo(shadowAfter); + } + + // Execute entitlement modification on other objects (if needed) + // Currently we use 'shadowAfter' both for removing and adding entitlements. In future, this behavior may become configurable. + executeEntitlementChangesModify(connector, resource, objectClassDefinition, shadowAfter, shadowAfter, scripts, itemDeltas, parentResult); parentResult.recordSuccess(); return sideEffectChanges; @@ -529,15 +540,15 @@ private void executeEntitlementChangesAdd(ConnectorInstance connector, ResourceT Map> roMap = new HashMap>(); RefinedResourceSchema rSchema = RefinedResourceSchema.getRefinedSchema(resource); - entitlementConverter.collectEntitlementsAsObjectOperation(roMap, objectClassDefinition, shadow, rSchema, resource); + entitlementConverter.collectEntitlementsAsObjectOperationInShadowAdd(roMap, objectClassDefinition, shadow, rSchema, resource); executeEntitlements(connector, resource, roMap, parentResult); } private void executeEntitlementChangesModify(ConnectorInstance connector, ResourceType resource, - RefinedObjectClassDefinition objectClassDefinition, PrismObject shadow, OperationProvisioningScriptsType scripts, - Collection objectDeltas, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, SecurityViolationException, ConfigurationException, ObjectAlreadyExistsException { + RefinedObjectClassDefinition objectClassDefinition, PrismObject shadowWhenRemovingEntitlement, PrismObject shadowWhenNotRemovingEntitlement, + OperationProvisioningScriptsType scripts, Collection objectDeltas, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, SecurityViolationException, ConfigurationException, ObjectAlreadyExistsException { Map> roMap = new HashMap>(); RefinedResourceSchema rSchema = RefinedResourceSchema.getRefinedSchema(resource); @@ -546,7 +557,7 @@ private void executeEntitlementChangesModify(ConnectorInstance connector, Resour if (new ItemPath(ShadowType.F_ASSOCIATION).equals(itemDelta.getPath())) { ContainerDelta containerDelta = (ContainerDelta)itemDelta; entitlementConverter.collectEntitlementsAsObjectOperation(roMap, containerDelta, objectClassDefinition, - shadow, rSchema, resource); + shadowWhenRemovingEntitlement, shadowWhenNotRemovingEntitlement, rSchema, resource); } } @@ -916,8 +927,8 @@ private boolean hasChangesOnResource( } - private void collectAttributeAndEntitlementChanges(Collection objectChange, - Collection operations, ResourceType resource, PrismObject shadow, + private void collectAttributeAndEntitlementChanges(Collection objectChange, + Collection operations, ResourceType resource, PrismObject shadow, RefinedObjectClassDefinition objectClassDefinition) throws SchemaException { if (operations == null) { operations = new ArrayList(); From fc7c455408ed8baece046351409cc9b749ea3485 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Fri, 27 Jun 2014 17:20:10 +0200 Subject: [PATCH 07/12] MID-1949: Reconciliation of associations --- .../RefinedAssociationDefinition.java | 8 + .../RefinedObjectClassDefinition.java | 10 +- .../schema/constants/SchemaConstants.java | 2 + .../xml/ns/public/common/common-3.xsd | 1 + .../model/impl/lens/AssignmentEvaluator.java | 2 +- .../model/impl/lens/EvaluatedAssignment.java | 2 +- .../model/impl/lens/ItemValueWithOrigin.java | 13 +- .../projector/ReconciliationProcessor.java | 329 ++++++++++++++++-- 8 files changed, 338 insertions(+), 29 deletions(-) diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAssociationDefinition.java b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAssociationDefinition.java index f09baab92b8..a77ea19b87c 100644 --- a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAssociationDefinition.java +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/RefinedAssociationDefinition.java @@ -68,4 +68,12 @@ public boolean isExclusiveStrong() { return BooleanUtils.isTrue(resourceObjectAssociationType.isExclusiveStrong()); } + public boolean isIgnored() { + return false; // todo implement! + } + + public boolean isTolerant() { + return BooleanUtils.isNotFalse(resourceObjectAssociationType.isTolerant()); + } + } 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 60534d178ad..daaa6a31586 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 @@ -232,6 +232,14 @@ public RefinedAssociationDefinition findEntitlementAssociation(QName name) { return null; } + public Collection getNamesOfAssociations() { + Collection names = new HashSet(); + for (RefinedAssociationDefinition assocDef : getAssociations()) { + names.add(assocDef.getName()); + } + return names; + } + public Collection getNamesOfAssociationsWithOutboundExpressions() { Collection names = new HashSet(); for (RefinedAssociationDefinition assocDef : getAssociations()) { @@ -242,7 +250,7 @@ public Collection getNamesOfAssociationsWithOutboundExpressions return names; } - public Collection getProtectedObjectPatterns() { + public Collection getProtectedObjectPatterns() { if (protectedObjectPatterns == null) { protectedObjectPatterns = new ArrayList(); } 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 48a4818832f..c3640aa7fbb 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 @@ -100,6 +100,7 @@ public abstract class SchemaConstants { public static final QName C_SHADOW = new QName(NS_C, "shadow"); public static final QName C_SHADOW_TYPE = new QName(NS_C, "ShadowType"); public static final QName C_ATTRIBUTES = new QName(NS_C, "attributes"); + public static final QName C_ASSOCIATION = new QName(NS_C, "association"); public static final QName C_CREDENTIALS_TYPE = new QName(NS_C, "CredentialsType"); public static final QName C_CREDENTIALS = new QName(NS_C, "credentials"); public static final QName C_ACTIVATION = new QName(NS_C, "activation"); @@ -133,6 +134,7 @@ public abstract class SchemaConstants { public static final ItemPath PATH_ACTIVATION_VALID_TO = new ItemPath(C_ACTIVATION, ActivationType.F_VALID_TO); public static final ItemPath PATH_ACTIVATION_DISABLE_REASON = new ItemPath(ShadowType.F_ACTIVATION, ActivationType.F_DISABLE_REASON); public static final ItemPath PATH_ATTRIBUTES = new ItemPath(C_ATTRIBUTES); + public static final ItemPath PATH_ASSOCIATION = new ItemPath(C_ASSOCIATION); public static final ItemPath PATH_TRIGGER = new ItemPath(ObjectType.F_TRIGGER); public static final String NS_PROVISIONING = NS_MIDPOINT_PUBLIC + "/provisioning"; 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 b3f3bd339c8..b27dc5b5014 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 @@ -5847,6 +5847,7 @@ + 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 920279264a3..3656330a581 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 @@ -210,7 +210,7 @@ private void evaluateAssignment(EvaluatedAssignment evalAssignment, AssignmentPa AssignmentPath assignmentPath, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException { assertSource(source, evalAssignment); - LOGGER.trace("Evaluate assignment {} (eval costr: {})", assignmentPath, assignmentPathSegment.isEvaluateConstructions()); + LOGGER.trace("Evaluate assignment {} (eval constr: {})", assignmentPath, assignmentPathSegment.isEvaluateConstructions()); AssignmentType assignmentType = assignmentPathSegment.getAssignmentType(); 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 226add43977..48fdb5f3eec 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 @@ -139,7 +139,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); - LOGGER.trace("Evaluating construction '{}' in {}", construction); + 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/ItemValueWithOrigin.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ItemValueWithOrigin.java index 8a653674c31..69acb6d796d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ItemValueWithOrigin.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ItemValueWithOrigin.java @@ -43,10 +43,21 @@ public ItemValueWithOrigin(V propertyValue, this.mapping = mapping; this.construction = accountConstruction; } - + + @Deprecated public V getPropertyValue() { return itemValue; } + + // the same as above, but with correct name + public V getItemValue() { + return itemValue; + } + + // use with care + public void setItemValue(V value) { + this.itemValue = value; + } public Mapping getMapping() { return mapping; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ReconciliationProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ReconciliationProcessor.java index e58b3c55d72..c81dffd94d4 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ReconciliationProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ReconciliationProcessor.java @@ -21,11 +21,15 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.xml.namespace.QName; +import com.evolveum.midpoint.common.refinery.RefinedAssociationDefinition; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.delta.ContainerDelta; +import com.evolveum.midpoint.util.PrettyPrinter; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAssociationType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -45,7 +49,6 @@ import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.prism.PrismPropertyValue; -import com.evolveum.midpoint.prism.PrismValue; import com.evolveum.midpoint.prism.delta.DeltaSetTriple; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.PropertyDelta; @@ -58,7 +61,6 @@ import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.util.MiscUtil; -import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.exception.CommunicationException; import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; @@ -111,11 +113,11 @@ void processReconciliation(LensContext context, // We can do this only for focal types. return; } - processReconciliationUser(context, projectionContext, result); + processReconciliationFocus(context, projectionContext, result); } - void processReconciliationUser(LensContext context, - LensProjectionContext accContext, OperationResult result) throws SchemaException, + void processReconciliationFocus(LensContext context, + LensProjectionContext accContext, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { @@ -153,18 +155,25 @@ void processReconciliationUser(LensContext context, accContext.recompute(); } + RefinedObjectClassDefinition accountDefinition = accContext.getRefinedAccountDefinition(); + Map>>> squeezedAttributes = accContext .getSqueezedAttributes(); - if (squeezedAttributes == null || squeezedAttributes.isEmpty()) { - return; - } - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Attribute reconciliation processing {}", accContext.getHumanReadableName()); - } + if (squeezedAttributes != null && !squeezedAttributes.isEmpty()) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Attribute reconciliation processing {}", accContext.getHumanReadableName()); + } + reconcileProjectionAttributes(accContext, squeezedAttributes, accountDefinition); + } + + Map>>> squeezedAssociations = accContext.getSqueezedAssociations(); + if (squeezedAssociations != null && !squeezedAssociations.isEmpty()) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Association reconciliation processing {}", accContext.getHumanReadableName()); + } + reconcileProjectionAssociations(accContext, squeezedAssociations, accountDefinition); + } - RefinedObjectClassDefinition accountDefinition = accContext.getRefinedAccountDefinition(); - reconcileProjection(accContext, squeezedAttributes, accountDefinition); } catch (RuntimeException e) { subResult.recordFatalError(e); throw e; @@ -176,10 +185,10 @@ void processReconciliationUser(LensContext context, } } - private void reconcileProjection( - LensProjectionContext projCtx, - Map>>> squeezedAttributes, - RefinedObjectClassDefinition accountDefinition) throws SchemaException { + private void reconcileProjectionAttributes( + LensProjectionContext projCtx, + Map>>> squeezedAttributes, + RefinedObjectClassDefinition accountDefinition) throws SchemaException { PrismObject shadowNew = projCtx.getObjectNew(); @@ -319,7 +328,194 @@ private void reconcileProjection( } } - private void decideIfTolerate(LensProjectionContext accCtx, + private void reconcileProjectionAssociations( + LensProjectionContext projCtx, + Map>>> squeezedAssociations, + RefinedObjectClassDefinition accountDefinition) throws SchemaException { + + PrismObject shadowNew = projCtx.getObjectNew(); + + PrismContainer associationsContainer = shadowNew.findContainer(ShadowType.F_ASSOCIATION); + + Collection associationNames = MiscUtil.union(squeezedAssociations.keySet(), accountDefinition.getNamesOfAssociations()); + + for (QName assocName : associationNames) { + LOGGER.trace("Association reconciliation processing association {}", assocName); + RefinedAssociationDefinition associationDefinition = accountDefinition.findAssociation(assocName); + if (associationDefinition == null) { + throw new SchemaException("No definition for association " + assocName + " in " + + projCtx.getResourceShadowDiscriminator()); + } + + DeltaSetTriple>> cvwoTriple = squeezedAssociations.get(assocName); + + // note: actually isIgnored is not implemented yet + if (associationDefinition.isIgnored()) { + LOGGER.trace("Skipping reconciliation of association {} because it is ignored", assocName); + continue; + } + + // TODO implement limitations +// PropertyLimitations limitations = associationDefinition.getLimitations(LayerType.MODEL); +// if (limitations != null) { +// PropertyAccessType access = limitations.getAccess(); +// if (access != null) { +// if (projCtx.isAdd() && (access.isAdd() == null || !access.isAdd())) { +// LOGGER.trace("Skipping reconciliation of attribute {} because it is non-createable", +// attrName); +// continue; +// } +// if (projCtx.isModify() && (access.isModify() == null || !access.isModify())) { +// LOGGER.trace("Skipping reconciliation of attribute {} because it is non-updateable", +// attrName); +// continue; +// } +// } +// } + + Collection>> shouldBeCValues; + if (cvwoTriple == null) { + shouldBeCValues = new ArrayList<>(); + } else { + shouldBeCValues = cvwoTriple.getNonNegativeValues(); + } + + // values in shouldBeCValues are parent-less + // to be able to make Containerable out of them, we provide them a (fake) parent + // (and we clone them not to mess anything) + + PrismContainer fakeParent = prismContext.getSchemaRegistry().findContainerDefinitionByCompileTimeClass(ShadowAssociationType.class).instantiate(); + for (ItemValueWithOrigin> cvwo : shouldBeCValues) { + PrismContainerValue cvalue = cvwo.getItemValue().clone(); + cvalue.setParent(fakeParent); + cvwo.setItemValue(cvalue); + } + + boolean hasStrongShouldBeCValue = false; + for (ItemValueWithOrigin> shouldBeCValue : shouldBeCValues) { + if (shouldBeCValue.getMapping() != null + && shouldBeCValue.getMapping().getStrength() == MappingStrengthType.STRONG) { + hasStrongShouldBeCValue = true; + break; + } + } + + Collection> areCValues = new HashSet<>(); + if (associationsContainer != null) { + for (Object o : associationsContainer.getValues()) { + PrismContainerValue existingAssocValue = (PrismContainerValue) o; + if (existingAssocValue.getValue().getName().equals(assocName)) { + areCValues.add(existingAssocValue); + } + } + } else { + areCValues = new HashSet<>(); + } + + // todo comment this logging code out eventually + if (LOGGER.isTraceEnabled()) { + StringBuilder sb = new StringBuilder(); + sb.append("Reconciliation\nASSOCIATION: ").append(PrettyPrinter.prettyPrint(assocName)); + sb.append("\n Should be:"); + for (ItemValueWithOrigin> shouldBeCValue : shouldBeCValues) { + sb.append("\n "); + sb.append(shouldBeCValue.getItemValue()); + Mapping shouldBeMapping = shouldBeCValue.getMapping(); + if (shouldBeMapping.getStrength() != MappingStrengthType.STRONG) { + sb.append(" STRONG"); + } + if (shouldBeMapping.getStrength() != MappingStrengthType.WEAK) { + sb.append(" WEAK"); + } + } + sb.append("\n Is:"); + for (PrismContainerValue isCVal : areCValues) { + sb.append("\n "); + sb.append(isCVal); + } + LOGGER.trace("{}", sb.toString()); + } + + ValueMatcher associationValueMatcher = new ValueMatcher(null) { + // todo is this correct? [med] + @Override + public boolean match(Object realA, Object realB) { + checkType(realA); + checkType(realB); + + if (realA == null) { + return realB == null; + } else if (realB == null) { + return false; + } else { + ShadowAssociationType a = (ShadowAssociationType) realA; + ShadowAssociationType b = (ShadowAssociationType) realB; + checkName(a); + checkName(b); + if (!a.getName().equals(b.getName())) { + return false; + } + if (a.getShadowRef() != null && a.getShadowRef().getOid() != null && b.getShadowRef() != null && b.getShadowRef().getOid() != null) { + return a.getShadowRef().getOid().equals(b.getShadowRef().getOid()); + } + LOGGER.warn("Comparing association values without shadowRefs: {} and {}", a, b); + return false; + } + } + + private void checkName(ShadowAssociationType s) { + if (s.getName() == null) { + throw new IllegalStateException("No name for association " + s); + } + } + + @Override + public boolean matches(Object realValue, String regex) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasRealValue(PrismProperty property, PrismPropertyValue pValue) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isRealValueToAdd(PropertyDelta delta, PrismPropertyValue pValue) { + throw new UnsupportedOperationException(); + } + + private void checkType(Object o) { + if (o != null && !(o instanceof ShadowAssociationType)) { + throw new IllegalStateException("Object is not a ShadowAssociationType, it is " + o.getClass() + " instead"); + } + } + }; + + for (ItemValueWithOrigin> shouldBeCvwo : shouldBeCValues) { + Mapping shouldBeMapping = shouldBeCvwo.getMapping(); + if (shouldBeMapping == null) { + continue; + } + if (shouldBeMapping.getStrength() != MappingStrengthType.STRONG + && (!areCValues.isEmpty() || hasStrongShouldBeCValue)) { + // weak or normal value and the attribute already has a + // value. Skip it. + // we cannot override it as it might have been legally + // changed directly on the projection resource object + continue; + } + ShadowAssociationType shouldBeRealValue = shouldBeCvwo.getItemValue().getValue(); + if (!isInAssociationValues(associationValueMatcher, shouldBeRealValue, areCValues)) { + recordAssociationDelta(associationValueMatcher, projCtx, associationDefinition, ModificationType.ADD, shouldBeRealValue, + shouldBeCvwo.getConstruction().getSource()); + } + } + + decideIfTolerateAssociation(projCtx, associationDefinition, areCValues, shouldBeCValues, associationValueMatcher); + } + } + + private void decideIfTolerate(LensProjectionContext accCtx, RefinedAttributeDefinition attributeDefinition, Collection> arePValues, Collection>> shouldBePValues, @@ -349,7 +545,23 @@ private void decideIfTolerate(LensProjectionContext accCtx, } - private boolean matchPattern(List patterns, + private void decideIfTolerateAssociation(LensProjectionContext accCtx, + RefinedAssociationDefinition associationDefinition, + Collection> areCValues, + Collection>> shouldBeCValues, + ValueMatcher valueMatcher) throws SchemaException { + + for (PrismContainerValue isCValue : areCValues){ + if (!associationDefinition.isTolerant()) { + if (!isInCvwoAssociationValues(valueMatcher, isCValue.getValue(), shouldBeCValues)) { + recordAssociationDelta(valueMatcher, accCtx, associationDefinition, ModificationType.DELETE, + isCValue.getValue(), null); + } + } + } + } + + private boolean matchPattern(List patterns, PrismPropertyValue isPValue, ValueMatcher valueMatcher) { if (patterns == null || patterns.isEmpty()) { return false; @@ -383,7 +595,7 @@ private void recordDelta(ValueMatcher valueMatcher, LensProjectionContext ac if (changeType == ModificationType.ADD) { attrDelta.addValueToAdd(pValue); } else if (changeType == ModificationType.DELETE) { - if (!isInDelta(existingDelta, valueMatcher, value)){ + if (!isToBeDeleted(existingDelta, valueMatcher, value)){ attrDelta.addValueToDelete(pValue); } @@ -396,7 +608,43 @@ private void recordDelta(ValueMatcher valueMatcher, LensProjectionContext ac accCtx.swallowToSecondaryDelta(attrDelta); } - private boolean isInDelta(ItemDelta existingDelta, ValueMatcher valueMatcher, T value) { + private void recordAssociationDelta(ValueMatcher valueMatcher, LensProjectionContext accCtx, + RefinedAssociationDefinition assocDef, ModificationType changeType, ShadowAssociationType value, ObjectType originObject) + throws SchemaException { + + ItemDelta existingDelta = null; + if (accCtx.getSecondaryDelta() != null) { + existingDelta = accCtx.getSecondaryDelta().findItemDelta(SchemaConstants.PATH_ASSOCIATION); + } + LOGGER.trace("Reconciliation will {} value of association {}: {}", new Object[] { changeType, assocDef, value }); + + // todo initialize only once + PrismContainerDefinition associationDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class) + .findContainerDefinition(ShadowType.F_ASSOCIATION); + + ContainerDelta assocDelta = new ContainerDelta(SchemaConstants.PATH_ASSOCIATION, associationDefinition); + + PrismContainerValue cValue = value.asPrismContainerValue().clone(); + cValue.setOriginType(OriginType.RECONCILIATION); + cValue.setOriginObject(originObject); + + if (changeType == ModificationType.ADD) { + assocDelta.addValueToAdd(cValue); + } else if (changeType == ModificationType.DELETE) { + if (!isToBeDeleted(existingDelta, valueMatcher, value)){ + assocDelta.addValueToDelete(cValue); + } + } else if (changeType == ModificationType.REPLACE) { + assocDelta.setValueToReplace(cValue); + } else { + throw new IllegalArgumentException("Unknown change type " + changeType); + } + + accCtx.swallowToSecondaryDelta(assocDelta); + } + + + private boolean isToBeDeleted(ItemDelta existingDelta, ValueMatcher valueMatcher, T value) { if (existingDelta == null) { return false; } @@ -431,7 +679,21 @@ private boolean isInValues(ValueMatcher valueMatcher, Object shouldBeValue, return false; } - private boolean isInPvwoValues(Object value, + // todo deduplicate; this was copied not to broke what works now [mederly] + private boolean isInAssociationValues(ValueMatcher valueMatcher, ShadowAssociationType shouldBeValue, + Collection> arePValues) { + if (arePValues == null || arePValues.isEmpty()) { + return false; + } + for (PrismContainerValue isPValue : arePValues) { + if (valueMatcher.match(isPValue.getValue(), shouldBeValue)) { + return true; + } + } + return false; + } + + private boolean isInPvwoValues(Object value, Collection>> shouldBePvwos) { for (ItemValueWithOrigin> shouldBePvwo : shouldBePvwos) { PrismPropertyValue shouldBePPValue = shouldBePvwo.getPropertyValue(); @@ -463,4 +725,21 @@ private boolean isInPvwoValues(ValueMatcher valueMatcher, Object value, return false; } + private boolean isInCvwoAssociationValues(ValueMatcher valueMatcher, ShadowAssociationType value, + Collection>> shouldBeCvwos) { + + if (shouldBeCvwos == null || shouldBeCvwos.isEmpty()) { + return false; + } + + for (ItemValueWithOrigin> shouldBeCvwo : shouldBeCvwos) { + PrismContainerValue shouldBePCValue = shouldBeCvwo.getItemValue(); + ShadowAssociationType shouldBeValue = shouldBePCValue.getValue(); + if (valueMatcher.match(value, shouldBeValue)) { + return true; + } + } + return false; + } + } From 199e714e934f1d0f52566dd1f29df51696b3f97d Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Sat, 28 Jun 2014 06:55:30 +0200 Subject: [PATCH 08/12] Fixing TestImportRecon.test510 (+ a few typos) --- .../src/main/resources/xml/ns/public/common/common-3.xsd | 8 ++++---- .../midpoint/model/impl/sync/SynchronizationService.java | 4 ++-- .../src/test/resources/common/resource-dummy.xml | 1 + 3 files changed, 7 insertions(+), 6 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 b27dc5b5014..9ffb2f5208a 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 @@ -4991,18 +4991,18 @@

Flag indicating if this synchronization specification is enabled. If it is not, then the system will ignore this definition. If enabled, the synchronization should start with most recent change - after enablinh synchronization. It will NOT pull in even the changes that + after enabling synchronization. It will NOT pull in even the changes that were done during disabled synchronization.

If this flag is not present the synchronization is assumed to be enabled. - This flag is meant to act as a tool to temprarily disable synchronizatoin without loosing the + This flag is meant to act as a tool to temporarily disable synchronization without loosing the configuration and and state or for forcing the synchronization engine to "skip" some changes.

Note that this is different than disabling/deleting the synchronization task. If the task - is stopped, midPont will not poll for changes at all. This means that the changes will + is stopped, midPoint will not poll for changes at all. This means that the changes will still be "pending" on the resource and once the task is enabled it will pull such changes. On the other hand, disabling synchronization using this flag and leaving the task running will - "acknowldge" all changes without doing anything.

+ "acknowledge" all changes without doing anything.

Also note that disabling synchronization using this flag will disable all the flavors, e.g. it will also disable import from resource.

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 903a95a8399..fdf4afe1be6 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 @@ -165,9 +165,9 @@ public void notifyChange(ResourceObjectShadowChangeDescription change, Task task boolean logDebug = isLogDebug(change); if (logDebug) { - LOGGER.debug("SYNCHRONIZATION: received change notifiation {}", change); + LOGGER.debug("SYNCHRONIZATION: received change notification {}", change); } else { - LOGGER.trace("SYNCHRONIZATION: received change notifiation {}", change); + LOGGER.trace("SYNCHRONIZATION: received change notification {}", change); } OperationResult subResult = parentResult.createSubresult(NOTIFY_CHANGE); diff --git a/model/model-intest/src/test/resources/common/resource-dummy.xml b/model/model-intest/src/test/resources/common/resource-dummy.xml index 8f8ac08b815..2370cecf4be 100644 --- a/model/model-intest/src/test/resources/common/resource-dummy.xml +++ b/model/model-intest/src/test/resources/common/resource-dummy.xml @@ -364,6 +364,7 @@ + ri:group From d062f494518cf2045caabf8ffa4ee93bd7a13cde Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Sat, 28 Jun 2014 07:48:44 +0200 Subject: [PATCH 09/12] More serious implementation of MID-1949, taking explicitReferentialIntegrity parameter into account. --- .../xml/ns/public/common/common-3.xsd | 13 +++++- .../impl/EntitlementConverter.java | 44 ++++++++++++++----- .../impl/ResourceObjectConverter.java | 19 ++++---- 3 files changed, 57 insertions(+), 19 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 9ffb2f5208a..4f87da6512d 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 @@ -3910,7 +3910,18 @@ - + + + + Whether you require midPoint to provide referential integrity for object-to-subject associations. + + Used for resources that do not provide referential integrity by themselves, e.g. for OpenDJ with + default settings (i.e. with referential integrity plugin turned off). + + For resources having referential integrity, e.g. for Active Directory, set this parameter to false. + + + diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/EntitlementConverter.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/EntitlementConverter.java index bdbf3a8a05f..483aabf8f1d 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/EntitlementConverter.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/EntitlementConverter.java @@ -22,6 +22,7 @@ import javax.xml.namespace.QName; +import org.apache.commons.lang.BooleanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -283,7 +284,7 @@ public void collectEntitlementsAsObjectOperationInShadowAdd(Map itemD public void collectEntitlementsAsObjectOperation(Map> roMap, ContainerDelta containerDelta, RefinedObjectClassDefinition objectClassDefinition, - PrismObject shadowWhenRemovingEntitlements, PrismObject shadowWhenNotRemovingEntitlements, RefinedResourceSchema rSchema, ResourceType resource) + PrismObject shadowBefore, PrismObject shadowAfter, RefinedResourceSchema rSchema, ResourceType resource) throws SchemaException { collectEntitlementsAsObjectOperation(roMap, containerDelta.getValuesToAdd(), objectClassDefinition, - shadowWhenNotRemovingEntitlements, rSchema, resource, ModificationType.ADD); + shadowBefore, shadowAfter, rSchema, resource, ModificationType.ADD); collectEntitlementsAsObjectOperation(roMap, containerDelta.getValuesToDelete(), objectClassDefinition, - shadowWhenRemovingEntitlements, rSchema, resource, ModificationType.DELETE); + shadowBefore, shadowAfter, rSchema, resource, ModificationType.DELETE); collectEntitlementsAsObjectOperation(roMap, containerDelta.getValuesToReplace(), objectClassDefinition, - shadowWhenNotRemovingEntitlements, rSchema, resource, ModificationType.REPLACE); + shadowBefore, shadowAfter, rSchema, resource, ModificationType.REPLACE); } ///////// @@ -347,13 +348,13 @@ public void collectEntitlementsAsObjectOperationDelete(ConnectorInstance con for (RefinedAssociationDefinition assocDefType: objectClassDefinition.getEntitlementAssociations()) { if (assocDefType.getResourceObjectAssociationType().getDirection() != ResourceObjectAssociationDirectionType.OBJECT_TO_SUBJECT) { // We can ignore these. They will die together with the object. No need to explicitly delete them. - LOGGER.trace("Ignoring object-to-subject association in deleted shadow"); + LOGGER.trace("Ignoring subject-to-object association in deleted shadow"); continue; } if (assocDefType.getResourceObjectAssociationType().isExplicitReferentialIntegrity() != null && !assocDefType.getResourceObjectAssociationType().isExplicitReferentialIntegrity()) { // Referential integrity not required for this one - LOGGER.trace("Ignoring association in deleted shadow because it has explicity referential integrity turned off"); + LOGGER.trace("Ignoring association in deleted shadow because it has explicit referential integrity turned off"); continue; } QName associationName = assocDefType.getName(); @@ -519,20 +520,20 @@ private void collectEntitlementToAttrDelta(Map> delt private void collectEntitlementsAsObjectOperation(Map> roMap, Collection> set, RefinedObjectClassDefinition objectClassDefinition, - PrismObject shadow, RefinedResourceSchema rSchema, ResourceType resource, ModificationType modificationType) + PrismObject shadowBefore, PrismObject shadowAfter, RefinedResourceSchema rSchema, ResourceType resource, ModificationType modificationType) throws SchemaException { if (set == null) { return; } for (PrismContainerValue associationCVal: set) { - collectEntitlementAsObjectOperation(roMap, associationCVal, objectClassDefinition, shadow, + collectEntitlementAsObjectOperation(roMap, associationCVal, objectClassDefinition, shadowBefore, shadowAfter, rSchema, resource, modificationType); } } private void collectEntitlementAsObjectOperation(Map> roMap, PrismContainerValue associationCVal, RefinedObjectClassDefinition objectClassDefinition, - PrismObject shadow, RefinedResourceSchema rSchema, ResourceType resource, ModificationType modificationType) + PrismObject shadowBefore, PrismObject shadowAfter, RefinedResourceSchema rSchema, ResourceType resource, ModificationType modificationType) throws SchemaException { ShadowAssociationType associationType = associationCVal.asContainerable(); @@ -585,6 +586,29 @@ private void collectEntitlementAsObjectOperation(Map shadow; + if (modificationType != ModificationType.DELETE) { + shadow = shadowAfter; + } else { + if (BooleanUtils.isFalse(assocDefType.getResourceObjectAssociationType().isExplicitReferentialIntegrity())) { + // i.e. resource has ref integrity by itself + shadow = shadowAfter; + } else { + shadow = shadowBefore; + } + } + ResourceAttribute valueAttr = ShadowUtil.getAttribute(shadow, valueAttrName); if (valueAttr == null) { // TODO: check schema and try to fetch full shadow if necessary 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 cfd74ea5d68..00837de6b02 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 @@ -400,11 +400,15 @@ public Collection modifyResourceObject( * State of the shadow before execution of the deltas - e.g. with original attributes, as it may be recorded in such a way in * groups of which this account is a member of. (In case of object->subject associations.) * - * Note: currently this is more-or-less hypothetical situation, because e.g. in AD the subject (account) - * is recorded in object (group) under his current DN -> the one that is in shadowAfter (below). - * So this is currently commented out. + * This is used when the resource does NOT provide referential integrity by itself. This is e.g. the case of OpenDJ with default + * settings. + * + * On the contrary, AD and OpenDJ with referential integrity plugin do provide automatic referential integrity, so this feature is + * not needed. + * + * We decide based on setting of explicitReferentialIntegrity in association definition. */ - //PrismObject shadowBefore = shadow.clone(); + PrismObject shadowBefore = shadow.clone(); collectAttributeAndEntitlementChanges(itemDeltas, operations, resource, shadow, objectClassDefinition); @@ -438,8 +442,7 @@ public Collection modifyResourceObject( } // Execute entitlement modification on other objects (if needed) - // Currently we use 'shadowAfter' both for removing and adding entitlements. In future, this behavior may become configurable. - executeEntitlementChangesModify(connector, resource, objectClassDefinition, shadowAfter, shadowAfter, scripts, itemDeltas, parentResult); + executeEntitlementChangesModify(connector, resource, objectClassDefinition, shadowBefore, shadowAfter, scripts, itemDeltas, parentResult); parentResult.recordSuccess(); return sideEffectChanges; @@ -547,7 +550,7 @@ private void executeEntitlementChangesAdd(ConnectorInstance connector, ResourceT } private void executeEntitlementChangesModify(ConnectorInstance connector, ResourceType resource, - RefinedObjectClassDefinition objectClassDefinition, PrismObject shadowWhenRemovingEntitlement, PrismObject shadowWhenNotRemovingEntitlement, + RefinedObjectClassDefinition objectClassDefinition, PrismObject shadowBefore, PrismObject shadowAfter, OperationProvisioningScriptsType scripts, Collection objectDeltas, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, SecurityViolationException, ConfigurationException, ObjectAlreadyExistsException { Map> roMap = new HashMap>(); @@ -557,7 +560,7 @@ private void executeEntitlementChangesModify(ConnectorInstance connector, Resour if (new ItemPath(ShadowType.F_ASSOCIATION).equals(itemDelta.getPath())) { ContainerDelta containerDelta = (ContainerDelta)itemDelta; entitlementConverter.collectEntitlementsAsObjectOperation(roMap, containerDelta, objectClassDefinition, - shadowWhenRemovingEntitlement, shadowWhenNotRemovingEntitlement, rSchema, resource); + shadowBefore, shadowAfter, rSchema, resource); } } From 025e32455cc5461f6fdc42b685554985ce6de77d Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Sat, 28 Jun 2014 07:53:12 +0200 Subject: [PATCH 10/12] Fixing gensync AD resource samples. --- samples/resources/ad/ad-resource-groups-advanced.xml | 3 ++- samples/resources/ad/ad-resource-groups-basic.xml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/samples/resources/ad/ad-resource-groups-advanced.xml b/samples/resources/ad/ad-resource-groups-advanced.xml index db77b9c028f..ea176fac1b8 100644 --- a/samples/resources/ad/ad-resource-groups-advanced.xml +++ b/samples/resources/ad/ad-resource-groups-advanced.xml @@ -163,6 +163,7 @@ objectToSubject ri:member icfs:name + false @@ -312,7 +313,7 @@ c:name - $shadow/attributes/sAMAccountName + $shadow/attributes/samAccountName diff --git a/samples/resources/ad/ad-resource-groups-basic.xml b/samples/resources/ad/ad-resource-groups-basic.xml index 1bfb6e3e35f..ac18d300384 100644 --- a/samples/resources/ad/ad-resource-groups-basic.xml +++ b/samples/resources/ad/ad-resource-groups-basic.xml @@ -163,6 +163,7 @@ objectToSubject ri:member icfs:name + false @@ -312,7 +313,7 @@ c:name - $shadow/attributes/sAMAccountName + $shadow/attributes/samAccountName From 5e196b4b5ebddecc6d0e00f26dd9eded8288048b Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Sun, 29 Jun 2014 01:11:58 +0200 Subject: [PATCH 11/12] Fixed logging in recon processor. --- .../impl/lens/projector/ReconciliationProcessor.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ReconciliationProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ReconciliationProcessor.java index c81dffd94d4..615de2ea5dc 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ReconciliationProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ReconciliationProcessor.java @@ -263,10 +263,10 @@ private void reconcileProjectionAttributes( // sb.append("\n "); // sb.append(shouldBePValue.getPropertyValue()); // Mapping shouldBeMapping = shouldBePValue.getMapping(); -// if (shouldBeMapping.getStrength() != MappingStrengthType.STRONG) { +// if (shouldBeMapping.getStrength() == MappingStrengthType.STRONG) { // sb.append(" STRONG"); // } -// if (shouldBeMapping.getStrength() != MappingStrengthType.WEAK) { +// if (shouldBeMapping.getStrength() == MappingStrengthType.WEAK) { // sb.append(" WEAK"); // } // } @@ -421,10 +421,10 @@ private void reconcileProjectionAssociations( sb.append("\n "); sb.append(shouldBeCValue.getItemValue()); Mapping shouldBeMapping = shouldBeCValue.getMapping(); - if (shouldBeMapping.getStrength() != MappingStrengthType.STRONG) { + if (shouldBeMapping.getStrength() == MappingStrengthType.STRONG) { sb.append(" STRONG"); } - if (shouldBeMapping.getStrength() != MappingStrengthType.WEAK) { + if (shouldBeMapping.getStrength() == MappingStrengthType.WEAK) { sb.append(" WEAK"); } } From 350d17555ad2e580af32b968745fae3770c09d42 Mon Sep 17 00:00:00 2001 From: Erik Suta Date: Mon, 30 Jun 2014 10:32:06 +0200 Subject: [PATCH 12/12] Small fix for buttons in assignment and add account popups on user details page --- .../page/admin/users/component/AssignablePopupContent.html | 4 ++-- .../web/page/admin/users/component/ResourcesPopup.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/component/AssignablePopupContent.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/component/AssignablePopupContent.html index 0034fb8126e..d649d432dfb 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/component/AssignablePopupContent.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/component/AssignablePopupContent.html @@ -28,9 +28,9 @@
-
+

-

+

\ No newline at end of file diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/component/ResourcesPopup.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/component/ResourcesPopup.html index 1b1b6f3faa7..5cea9ca6ec1 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/component/ResourcesPopup.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/component/ResourcesPopup.html @@ -28,9 +28,9 @@
-
+

\ No newline at end of file