diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.html index b2e3cdc0d47..c89ec6c9844 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.html @@ -54,6 +54,7 @@
+
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.java index cc42831fbee..3b436f2aec8 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.java @@ -42,6 +42,7 @@ import com.evolveum.midpoint.web.page.PageBase; import com.evolveum.midpoint.web.page.admin.configuration.component.ChooseTypePanel; import com.evolveum.midpoint.web.page.admin.dto.ObjectViewDto; +import com.evolveum.midpoint.web.page.admin.users.dto.UserDtoStatus; import com.evolveum.midpoint.web.util.WebMiscUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; @@ -97,6 +98,7 @@ public class AssignmentEditorPanel extends SimplePanel { private static final String ID_DESCRIPTION = "description"; private static final String ID_RELATION_CONTAINER = "relationContainer"; private static final String ID_RELATION = "relation"; + private static final String ID_RELATION_LABEL = "relationLabel"; private static final String ID_ADMINISTRATIVE_STATUS = "administrativeStatus"; private static final String ID_VALID_FROM = "validFrom"; private static final String ID_VALID_TO = "validTo"; @@ -343,8 +345,38 @@ public boolean isVisible() { "AssignmentEditorPanel.member", "AssignmentEditorPanel.manager", null); relation.setOutputMarkupId(true); relation.setOutputMarkupPlaceholderTag(true); + relation.add(new VisibleEnableBehaviour(){ + + @Override + public boolean isVisible() { + return isCreatingNewAssignment(); + } + }); relationContainer.add(relation); + Label relationLabel = new Label(ID_RELATION_LABEL, new AbstractReadOnlyModel() { + + @Override + public String getObject() { + if(getModel() == null || getModel().getObject() == null){ + return getString("AssignmentEditorPanel.relation.notSpecified"); + } + + AssignmentEditorDto object = getModel().getObject(); + return object.isOrgUnitManager() ? getString("AssignmentEditorPanel.manager") : getString("AssignmentEditorPanel.member"); + } + }); + relationLabel.setOutputMarkupId(true); + relationLabel.setOutputMarkupPlaceholderTag(true); + relationLabel.add(new VisibleEnableBehaviour(){ + + @Override + public boolean isVisible() { + return !isCreatingNewAssignment(); + } + }); + relationContainer.add(relationLabel); + WebMarkupContainer tenantRefContainer = new WebMarkupContainer(ID_CONTAINER_TENANT_REF); ChooseTypePanel tenantRef = new ChooseTypePanel(ID_TENANT_CHOOSER, new PropertyModel(getModel(), AssignmentEditorDto.F_TENANT_REF)){ @@ -738,4 +770,16 @@ private void showErrorPerformed(AjaxRequestTarget target){ error(getString("AssignmentEditorPanel.targetError")); target.add(getPageBase().getFeedbackPanel()); } + + /** + * Override to provide the information if object that contains this assignment + * is being edited or created. + * */ + protected boolean isCreatingNewAssignment(){ + if(getModelObject() == null){ + return false; + } + + return UserDtoStatus.ADD.equals(getModelObject().getStatus()); + } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.properties index 80461f2a5d2..89c82353f22 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/assignment/AssignmentEditorPanel.properties @@ -28,6 +28,7 @@ AssignmentEditorPanel.tenantRef=Tenant AssignmentEditorPanel.name.focus=(focus mapping) AssignmentEditorPanel.name.noTarget=(no target) AssignmentEditorPanel.showMore=Show more +AssignmentEditorPanel.relation.notSpecified="Not specified" AssignmentEditorPanel.member=Member AssignmentEditorPanel.manager=Manager AssignmentEditorPanel.targetError=Assignment target was not found. Either target oid is malformed or target object does not exist. diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java index 6d8d9d24ca6..a496833dc01 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java @@ -149,7 +149,7 @@ protected IModel createPageTitleModel(){ @Override protected String load() { - if(!isEditing()){ + if(!isEditingRole()){ return createStringResource("PageRoleEditor.title.newRole").getObject(); } @@ -164,7 +164,7 @@ protected IModel createPageSubTitleModel(){ @Override protected String load() { - if(!isEditing()){ + if(!isEditingRole()){ return createStringResource("PageRoleEditor.subtitle.newRole").getObject(); } @@ -179,7 +179,7 @@ private PrismObject loadRole(){ PrismObject role = null; try { - if (!isEditing()) { + if (!isEditingRole()) { RoleType r = new RoleType(); ActivationType defaultActivation = new ActivationType(); defaultActivation.setAdministrativeStatus(ActivationStatusType.ENABLED); @@ -211,7 +211,7 @@ private PrismObject loadRole(){ private ContainerWrapper loadRoleWrapper(){ OperationResult result = new OperationResult(OPERATION_CREATE_ROLE_WRAPPER); - ContainerStatus status = isEditing() ? ContainerStatus.MODIFYING : ContainerStatus.ADDING; + ContainerStatus status = isEditingRole() ? ContainerStatus.MODIFYING : ContainerStatus.ADDING; ObjectWrapper wrapper = null; ContainerWrapper extensionContainer = null; PrismObject role = model.getObject(); @@ -241,7 +241,7 @@ private ContainerWrapper loadRoleWrapper(){ return extensionContainer; } - private boolean isEditing(){ + private boolean isEditingRole(){ StringValue oid = getPageParameters().get(OnePageParameterEncoder.PARAMETER); return oid != null && StringUtils.isNotEmpty(oid.toString()); } @@ -440,7 +440,7 @@ private void savePerformed(AjaxRequestTarget target){ PrismObject newRole = model.getObject(); delta = null; - if (!isEditing()) { + if (!isEditingRole()) { //handle assignments PrismObjectDefinition orgDef = newRole.getDefinition(); @@ -478,7 +478,7 @@ private void savePerformed(AjaxRequestTarget target){ ObjectDelta extDelta = null; if(extensionDelta != null){ - if(isEditing()){ + if(isEditingRole()){ extDelta = extensionDelta; } else { extDelta = delta.getObjectToAdd().diff(extensionDelta.getObjectToAdd()); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageOrgUnit.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageOrgUnit.java index 5a741d7ebda..bea532d72b1 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageOrgUnit.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageOrgUnit.java @@ -206,7 +206,7 @@ protected ContainerWrapper load() { } }; - //status = isEditing() ? ContainerStatus.MODIFYING : ContainerStatus.ADDING; + //status = isEditingOrgUnit() ? ContainerStatus.MODIFYING : ContainerStatus.ADDING; initLayout(); } @@ -217,7 +217,7 @@ protected IModel createPageTitleModel() { @Override protected String load() { - if (!isEditing()) { + if (!isEditingOrgUnit()) { return PageOrgUnit.super.createPageTitleModel().getObject(); } @@ -229,7 +229,7 @@ protected String load() { private ContainerWrapper loadExtensionWrapper(){ OperationResult result = new OperationResult(OPERATION_LOAD_EXTENSION_WRAPPER); - ContainerStatus status = isEditing() ? ContainerStatus.MODIFYING : ContainerStatus.ADDING; + ContainerStatus status = isEditingOrgUnit() ? ContainerStatus.MODIFYING : ContainerStatus.ADDING; ObjectWrapper wrapper; ContainerWrapper extensionWrapper = null; PrismObject org = orgModel.getObject(); @@ -376,7 +376,7 @@ protected ObjectQuery createChooseQuery(){ } } - if(isEditing()){ + if(isEditingOrgUnit()){ oidList.add(orgModel.getObject().asObjectable().getOid()); } @@ -533,7 +533,7 @@ public void onClick(AjaxRequestTarget target) { form.add(new ExecuteChangeOptionsPanel(ID_EXECUTE_OPTIONS, executeOptionsModel, true, false)); // TODO add "show reconcile affected" when implemented for Orgs } - private boolean isEditing() { + private boolean isEditingOrgUnit() { StringValue oid = getPageParameters().get(OnePageParameterEncoder.PARAMETER); return oid != null && StringUtils.isNotEmpty(oid.toString()); } @@ -595,7 +595,7 @@ private PrismObject buildUnitFromModel(List parent } //Delete parentOrgUnits from edited OrgUnit - if(isEditing()){ + if(isEditingOrgUnit()){ if(parentOrgUnitsModel != null && parentOrgUnitsModel.getObject() != null){ for(ObjectReferenceType parent: parentOrgList){ if(!isRefInParentOrgModel(parent)){ @@ -636,7 +636,7 @@ private void savePerformed(AjaxRequestTarget target) { reviveModels(); delta = null; - if (!isEditing()) { + if (!isEditingOrgUnit()) { newOrgUnit = buildUnitFromModel(null); //handle assignments @@ -674,7 +674,7 @@ private void savePerformed(AjaxRequestTarget target) { ObjectDelta extDelta = null; if(extensionDelta != null){ - if(isEditing()){ + if(isEditingOrgUnit()){ extDelta = extensionDelta; } else { extDelta = delta.getObjectToAdd().diff(extensionDelta.getObjectToAdd()); @@ -748,7 +748,7 @@ private PrismObject loadOrgUnit(PrismObject unitToEdit) { PrismObject org = null; try { - if (!isEditing()) { + if (!isEditingOrgUnit()) { if (unitToEdit == null) { OrgType o = new OrgType(); ActivationType defaultActivation = new ActivationType(); diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/LayerRefinedObjectClassDefinition.java b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/LayerRefinedObjectClassDefinition.java index d34f16ba413..78ee0ce679c 100644 --- a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/LayerRefinedObjectClassDefinition.java +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/LayerRefinedObjectClassDefinition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2015 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceActivationDefinitionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceBidirectionalMappingType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectAssociationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; @@ -615,8 +616,13 @@ public void add(RefinedAttributeDefinition refinedAttributeDefinition) { public void parseAssociations(RefinedResourceSchema rSchema) { throw new UnsupportedOperationException(); } - + @Override + public ResourceObjectReferenceType getBaseContext() { + return refinedObjectClassDefinition.getBaseContext(); + } + + @Override protected String debugDump(int indent, LayerType layer) { return refinedObjectClassDefinition.debugDump(indent, layer); } 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 2ce0d6ef0f1..856b70e376c 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2015 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,9 @@ import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.QNameUtil; +import com.evolveum.midpoint.util.exception.ConfigurationException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.Trace; @@ -69,6 +71,7 @@ public class RefinedObjectClassDefinition extends ObjectClassComplexTypeDefiniti private Collection protectedObjectPatterns; private List attributeDefinitions; private Collection associations = new ArrayList(); + private ResourceObjectReferenceType baseContext; /** * Refined object definition. The "any" parts are replaced with appropriate schema (e.g. resource schema) @@ -352,7 +355,15 @@ public PrismObjectDefinition getObjectDefinition() { return objectDefinition; } - private void constructObjectDefinition() { + public ResourceObjectReferenceType getBaseContext() { + return baseContext; + } + + public void setBaseContext(ResourceObjectReferenceType baseContext) { + this.baseContext = baseContext; + } + + private void constructObjectDefinition() { // Almost-shallow clone of object definition and complex type PrismObjectDefinition originalObjectDefinition = getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class); @@ -537,6 +548,10 @@ private static RefinedObjectClassDefinition parseRefinedObjectClass(ResourceObje rOcDef.setDefault(objectClassDef.isDefaultInAKind()); } + if (schemaHandlingObjDefType.getBaseContext() != null) { + rOcDef.setBaseContext(schemaHandlingObjDefType.getBaseContext()); + } + for (ResourceAttributeDefinition road : objectClassDef.getAttributeDefinitions()) { String attrContextDescription = road.getName() + ", in " + contextDescription; ResourceAttributeDefinitionType attrDefType = findAttributeDefinitionType(road.getName(), schemaHandlingObjDefType, @@ -761,6 +776,37 @@ public AttributeFetchStrategyType getActivationFetchStrategy(QName propertyName) return biType.getFetchStrategy(); } + public static RefinedObjectClassDefinition determineObjectClassDefinition(PrismObject shadow, ResourceType resource) throws SchemaException, ConfigurationException { + ShadowType shadowType = shadow.asObjectable(); + RefinedResourceSchema refinedSchema = RefinedResourceSchema.getRefinedSchema(resource, resource.asPrismObject().getPrismContext()); + if (refinedSchema == null) { + throw new ConfigurationException("No schema defined for "+resource); + } + + + RefinedObjectClassDefinition objectClassDefinition = null; + ShadowKindType kind = shadowType.getKind(); + String intent = shadowType.getIntent(); + QName objectClass = shadow.asObjectable().getObjectClass(); + if (kind != null) { + objectClassDefinition = refinedSchema.getRefinedDefinition(kind, intent); + } + if (objectClassDefinition == null) { + // Fallback to objectclass only + if (objectClass == null) { + throw new SchemaException("No kind nor objectclass definied in "+shadow); + } + objectClassDefinition = refinedSchema.findRefinedDefinitionByObjectClassQName(kind, objectClass); + } + + if (objectClassDefinition == null) { + throw new SchemaException("Definition for "+shadow+" not found (objectClass=" + PrettyPrinter.prettyPrint(objectClass) + + ", kind="+kind+", intent='"+intent+"') in schema of " + resource); + } + + return objectClassDefinition; + } + public boolean matches(ShadowType shadowType) { if (shadowType == null) { return false; diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceObjectIdentification.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceObjectIdentification.java new file mode 100644 index 00000000000..92fbee12230 --- /dev/null +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/ResourceObjectIdentification.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.schema.processor; + +import java.util.Collection; + +/** + * @author semancik + * + */ +public class ResourceObjectIdentification { + + private ObjectClassComplexTypeDefinition objectClassDefinition; + private Collection> identifiers; + // TODO: identification strategy + + public ResourceObjectIdentification(ObjectClassComplexTypeDefinition objectClassDefinition, Collection> identifiers) { + this.objectClassDefinition = objectClassDefinition; + this.identifiers = identifiers; + } + + public Collection> getIdentifiers() { + return identifiers; + } + + public ObjectClassComplexTypeDefinition getObjectClassDefinition() { + return objectClassDefinition; + } + +} diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SearchHierarchyConstraints.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SearchHierarchyConstraints.java new file mode 100644 index 00000000000..09bd4eed16d --- /dev/null +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SearchHierarchyConstraints.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.schema.processor; + +/** + * @author semancik + * + */ +public class SearchHierarchyConstraints { + + ResourceObjectIdentification baseContext; + SearchHierarchyScope scope; + + public SearchHierarchyConstraints(ResourceObjectIdentification baseContext, SearchHierarchyScope scope) { + super(); + this.baseContext = baseContext; + this.scope = scope; + } + + public ResourceObjectIdentification getBaseContext() { + return baseContext; + } + + public SearchHierarchyScope getScope() { + return scope; + } + + +} diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SearchHierarchyScope.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SearchHierarchyScope.java new file mode 100644 index 00000000000..44fc362f8f6 --- /dev/null +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/processor/SearchHierarchyScope.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.schema.processor; + +/** + * @author semancik + * + */ +public enum SearchHierarchyScope { + ONE, SUBTREE; +} diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ShadowUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ShadowUtil.java index fb1347adf1e..22cf21e5277 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ShadowUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ShadowUtil.java @@ -67,6 +67,23 @@ public static Collection> getSecondaryIdentifiers(PrismObje return attributesContainer.getSecondaryIdentifiers(); } + public static ResourceAttribute getSecondaryIdentifier(ObjectClassComplexTypeDefinition objectClassDefinition, + Collection> identifiers) throws SchemaException { + if (identifiers == null) { + return null; + } + ResourceAttribute secondaryIdentifier = null; + for (ResourceAttribute identifier: identifiers) { + if (identifier.getDefinition().isIdentifier(objectClassDefinition)) { + if (secondaryIdentifier != null) { + throw new SchemaException("More than one secondary identifier in "+objectClassDefinition); + } + secondaryIdentifier = identifier; + } + } + return secondaryIdentifier; + } + public static ResourceAttribute getNamingAttribute(ShadowType shadow){ return getNamingAttribute(shadow.asPrismObject()); } 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 0ba6c2d576e..40faada7313 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 @@ -3289,6 +3289,17 @@ + + + + The definition of base context (resource object container). This object will be used + as a base for searches for objects of this type. Usually only the objects that are + hierarchically below the baseContext are returned by such a search. + E.g. this is used to specify LDAP organizationalUnit that contains users or groups + of particular type. + + + @@ -4103,6 +4114,134 @@ + + + + Reference to a resource object. This reference has many properties that influence when and how + to look for the object. We assume that the search for resource objects is quite expensive, therefore + we will need to optimize the number of searches. We also want this reference to be "sticky", e.g. to + survive resource object renames. + + + + + + + + + + The filter used to look for the object. This filter does NOT need to contain + clauses for resource. This will be automatically added by midpoint. In some situation also + the clause for objectClass may be omitted (if it can be determined by other means). + + + + + + + Reference to shadow that represents the resource object. If present, then it will be + used directly. If not present then the search filter will be used to locate the shadow + and the the result will be set to this reference. + + + tns:ShadowType + + + + + + + + + + + + + + The strategy used to resolve resource object references. + + + + + + + + + + Search only in midPoint identity repository. Do not look at the resource. + + + + + + + + + + Look only at the resource. + + + + + + + + + + Search in midPoint identity repository first. If the shadow is found, use it. + If the shadow is not found also search on the resource. + + + + + + + + + + + + + The strategy used to resolve resource object references. + + + + + + + + + + Never resolve reference. If it has shadowRef then use it. If it does not then throw an error. + + + + + + + + + + Resolve reference once. Then store the OID. Use the OID in subsequent cases. + + + + + + + + + + Always reselve the reference. Do not store the OID. + + + + + + + + + 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 8e0462b3873..9f6d38f82e7 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 @@ -56,14 +56,19 @@ import com.evolveum.midpoint.provisioning.util.ProvisioningUtil; import com.evolveum.midpoint.schema.processor.ResourceAttribute; import com.evolveum.midpoint.schema.processor.ResourceAttributeContainer; +import com.evolveum.midpoint.schema.processor.ResourceObjectIdentification; +import com.evolveum.midpoint.schema.processor.SearchHierarchyConstraints; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ShadowUtil; import com.evolveum.midpoint.util.exception.CommunicationException; +import com.evolveum.midpoint.util.exception.ConfigurationException; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.TunnelException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectAssociationDirectionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectReferenceType; 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; @@ -82,6 +87,9 @@ class EntitlementConverter { private static final Trace LOGGER = TraceManager.getTrace(EntitlementConverter.class); + @Autowired(required=true) + private ResourceObjectReferenceResolver resourceObjectReferenceResolver; + @Autowired(required=true) private PrismContext prismContext; @@ -93,7 +101,7 @@ class EntitlementConverter { ///////// public void postProcessEntitlementsRead(ConnectorInstance connector, ResourceType resourceType, - PrismObject resourceObject, RefinedObjectClassDefinition objectClassDefinition, OperationResult parentResult) throws SchemaException, CommunicationException, GenericFrameworkException { + PrismObject resourceObject, RefinedObjectClassDefinition objectClassDefinition, OperationResult parentResult) throws SchemaException, CommunicationException, GenericFrameworkException, ObjectNotFoundException, ConfigurationException { Collection entitlementAssociationDefs = objectClassDefinition.getEntitlementAssociations(); if (entitlementAssociationDefs != null) { @@ -173,7 +181,7 @@ private void postProcessEntitlementEntitlementToSubject RefinedObjectClassDefinition objectClassDefinition, RefinedAssociationDefinition assocDefType, final RefinedObjectClassDefinition entitlementDef, ResourceAttributeContainer attributesContainer, final PrismContainer associationContainer, - OperationResult parentResult) throws SchemaException, CommunicationException, GenericFrameworkException { + OperationResult parentResult) throws SchemaException, CommunicationException, GenericFrameworkException, ObjectNotFoundException, ConfigurationException { final QName associationName = assocDefType.getName(); if (associationName == null) { throw new SchemaException("No name in entitlement association "+assocDefType+" in "+resourceType); @@ -204,6 +212,17 @@ private void postProcessEntitlementEntitlementToSubject AttributesToReturn attributesToReturn = ProvisioningUtil.createAttributesToReturn(entitlementDef, resourceType); + SearchHierarchyConstraints searchHierarchyConstraints = null; + ResourceObjectReferenceType baseContextRef = entitlementDef.getBaseContext(); + if (baseContextRef != null) { + // TODO: this should be done once per search. Not in every run of postProcessEntitlementEntitlementToSubject + // this has to go outside of this method + PrismObject baseContextShadow = resourceObjectReferenceResolver.resolve(baseContextRef, "base context specification in "+entitlementDef, parentResult); + RefinedObjectClassDefinition baseContextObjectClassDefinition = RefinedObjectClassDefinition.determineObjectClassDefinition(baseContextShadow, resourceType); + ResourceObjectIdentification baseContextIdentification = new ResourceObjectIdentification(baseContextObjectClassDefinition, ShadowUtil.getIdentifiers(baseContextShadow)); + searchHierarchyConstraints = new SearchHierarchyConstraints(baseContextIdentification, null); + } + ResultHandler handler = new ResultHandler() { @Override public boolean handle(PrismObject entitlementShadow) { @@ -234,7 +253,7 @@ public boolean handle(PrismObject entitlementShadow) { LOGGER.trace("Processed entitlement-to-subject association for account {}: query {}", ShadowUtil.getHumanReadableName(resourceObject), query); } - connector.search(entitlementDef, query, handler, attributesToReturn, null, parentResult); + connector.search(entitlementDef, query, handler, attributesToReturn, null, searchHierarchyConstraints, parentResult); } catch (TunnelException e) { throw (SchemaException)e.getCause(); } @@ -328,13 +347,12 @@ public void collectEntitlementsAsObjectOperation(Map void collectEntitlementsAsObjectOperationDelete(ConnectorInstance connector, final Map> roMap, RefinedObjectClassDefinition objectClassDefinition, PrismObject shadow, RefinedResourceSchema rSchema, ResourceType resourceType, OperationResult parentResult) - throws SchemaException, CommunicationException { + throws SchemaException, CommunicationException, ObjectNotFoundException, ConfigurationException { Collection entitlementAssociationDefs = objectClassDefinition.getEntitlementAssociations(); if (entitlementAssociationDefs == null || entitlementAssociationDefs.isEmpty()) { @@ -396,6 +414,15 @@ public void collectEntitlementsAsObjectOperationDelete(ConnectorInstance con AttributesToReturn attributesToReturn = ProvisioningUtil.createAttributesToReturn(entitlementOcDef, resourceType); + SearchHierarchyConstraints searchHierarchyConstraints = null; + ResourceObjectReferenceType baseContextRef = entitlementOcDef.getBaseContext(); + if (baseContextRef != null) { + PrismObject baseContextShadow = resourceObjectReferenceResolver.resolve(baseContextRef, "base context specification in "+entitlementOcDef, parentResult); + RefinedObjectClassDefinition baseContextObjectClassDefinition = RefinedObjectClassDefinition.determineObjectClassDefinition(baseContextShadow, resourceType); + ResourceObjectIdentification baseContextIdentification = new ResourceObjectIdentification(baseContextObjectClassDefinition, ShadowUtil.getIdentifiers(baseContextShadow)); + searchHierarchyConstraints = new SearchHierarchyConstraints(baseContextIdentification, null); + } + ResultHandler handler = new ResultHandler() { @Override public boolean handle(PrismObject entitlementShadow) { @@ -430,7 +457,7 @@ public boolean handle(PrismObject entitlementShadow) { }; try { LOGGER.trace("Searching for associations in deleted shadow, query: {}", query); - connector.search(entitlementOcDef, query, handler, attributesToReturn, null, parentResult); + connector.search(entitlementOcDef, query, handler, attributesToReturn, null, searchHierarchyConstraints, parentResult); } catch (TunnelException e) { throw (SchemaException)e.getCause(); } catch (GenericFrameworkException e) { 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 4e27a86a3de..b66b390c4a8 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 @@ -79,7 +79,9 @@ import com.evolveum.midpoint.schema.processor.ResourceAttribute; import com.evolveum.midpoint.schema.processor.ResourceAttributeContainer; import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceObjectIdentification; import com.evolveum.midpoint.schema.processor.ResourceSchema; +import com.evolveum.midpoint.schema.processor.SearchHierarchyConstraints; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.schema.util.ResourceTypeUtil; @@ -104,6 +106,7 @@ 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.ResourceObjectReferenceType; 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; @@ -137,6 +140,9 @@ public class ResourceObjectConverter { @Autowired(required=true) private MatchingRuleRegistry matchingRuleRegistry; + + @Autowired(required=true) + private ResourceObjectReferenceResolver resourceObjectReferenceResolver; @Autowired(required=true) private PrismContext prismContext; @@ -221,7 +227,7 @@ public boolean handle(PrismObject shadow) { } }; try { - connector.search(objectClassDefinition, query, handler, attributesToReturn, null, parentResult); + connector.search(objectClassDefinition, query, handler, attributesToReturn, null, null, parentResult); if (shadowHolder.isEmpty()) { throw new ObjectNotFoundException("No object found for secondary identifier "+secondaryIdentifier); } @@ -982,6 +988,14 @@ public SearchResultMetadata searchResourceObjects(final ConnectorInstance connec CommunicationException, ObjectNotFoundException, ConfigurationException { AttributesToReturn attributesToReturn = ProvisioningUtil.createAttributesToReturn(objectClassDef, resourceType); + SearchHierarchyConstraints searchHierarchyConstraints = null; + ResourceObjectReferenceType baseContextRef = objectClassDef.getBaseContext(); + if (baseContextRef != null) { + PrismObject baseContextShadow = resourceObjectReferenceResolver.resolve(baseContextRef, "base context specification in "+objectClassDef, parentResult); + RefinedObjectClassDefinition baseContextObjectClassDefinition = RefinedObjectClassDefinition.determineObjectClassDefinition(baseContextShadow, resourceType); + ResourceObjectIdentification baseContextIdentification = new ResourceObjectIdentification(baseContextObjectClassDefinition, ShadowUtil.getIdentifiers(baseContextShadow)); + searchHierarchyConstraints = new SearchHierarchyConstraints(baseContextIdentification, null); + } ResultHandler innerResultHandler = new ResultHandler() { @Override @@ -997,6 +1011,10 @@ public boolean handle(PrismObject shadow) { throw new TunnelException(e); } catch (GenericFrameworkException e) { throw new TunnelException(e); + } catch (ObjectNotFoundException e) { + throw new TunnelException(e); + } catch (ConfigurationException e) { + throw new TunnelException(e); } return resultHandler.handle(shadow); } finally { @@ -1007,7 +1025,8 @@ public boolean handle(PrismObject shadow) { SearchResultMetadata metadata = null; try { - metadata = connector.search(objectClassDef, query, innerResultHandler, attributesToReturn, objectClassDef.getPagedSearches(), parentResult); + metadata = connector.search(objectClassDef, query, innerResultHandler, attributesToReturn, + objectClassDef.getPagedSearches(), searchHierarchyConstraints, parentResult); } catch (GenericFrameworkException e) { parentResult.recordFatalError("Generic error in the connector: " + e.getMessage(), e); throw new SystemException("Generic error in the connector: " + e.getMessage(), e); @@ -1023,6 +1042,10 @@ public boolean handle(PrismObject shadow) { throw (SchemaException)cause; } else if (cause instanceof CommunicationException) { throw (CommunicationException)cause; + } else if (cause instanceof ObjectNotFoundException) { + throw (ObjectNotFoundException)cause; + } else if (cause instanceof ConfigurationException) { + throw (ConfigurationException)cause; } if (cause instanceof GenericFrameworkException) { new GenericConnectorException(cause.getMessage(), cause); } else { @@ -1077,7 +1100,8 @@ private PrismObject fetchResourceObject(ConnectorInstance connector, throw new UnsupportedOperationException("Resource does not support 'read' operation"); } - PrismObject resourceObject = connector.fetchObject(ShadowType.class, objectClassDefinition, identifiers, + ResourceObjectIdentification identification = new ResourceObjectIdentification(objectClassDefinition, identifiers); + PrismObject resourceObject = connector.fetchObject(ShadowType.class, identification, attributesToReturn, parentResult); return postProcessResourceObjectRead(connector, resource, resourceObject, objectClassDefinition, fetchAssociations, parentResult); } catch (ObjectNotFoundException e) { @@ -1426,7 +1450,7 @@ private boolean isAttributeDelta(ItemDelta itemDelta) { public List> fetchChanges(ConnectorInstance connector, ResourceType resource, RefinedObjectClassDefinition objectClass, PrismProperty lastToken, OperationResult parentResult) throws SchemaException, - CommunicationException, ConfigurationException, SecurityViolationException, GenericFrameworkException { + CommunicationException, ConfigurationException, SecurityViolationException, GenericFrameworkException, ObjectNotFoundException { Validate.notNull(resource, "Resource must not be null."); Validate.notNull(parentResult, "Operation result must not be null."); @@ -1477,7 +1501,7 @@ public List> fetchChanges(ConnectorInstance connector, Resour */ private PrismObject postProcessResourceObjectRead(ConnectorInstance connector, ResourceType resourceType, PrismObject resourceObject, RefinedObjectClassDefinition objectClassDefinition, boolean fetchAssociations, - OperationResult parentResult) throws SchemaException, CommunicationException, GenericFrameworkException { + OperationResult parentResult) throws SchemaException, CommunicationException, GenericFrameworkException, ObjectNotFoundException, ConfigurationException { ShadowType resourceObjectType = resourceObject.asObjectable(); setProtectedFlag(resourceType, objectClassDefinition, resourceObject); diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectReferenceResolver.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectReferenceResolver.java new file mode 100644 index 00000000000..c93297f6dd7 --- /dev/null +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ResourceObjectReferenceResolver.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015 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.provisioning.impl; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectReferenceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; + +/** + * @author semancik + * + */ +@Component +public class ResourceObjectReferenceResolver { + + @Autowired(required = true) + @Qualifier("cacheRepositoryService") + private RepositoryService repositoryService; + + PrismObject resolve(ResourceObjectReferenceType resourceObjectReference, String desc, OperationResult result) throws ObjectNotFoundException, SchemaException { + if (resourceObjectReference == null) { + return null; + } + ObjectReferenceType shadowRef = resourceObjectReference.getShadowRef(); + if (shadowRef == null || shadowRef.getOid() == null) { + throw new ObjectNotFoundException("No shadowRef OID in "+desc); + } + // TODO: implement resolution strategies + PrismObject shadow = repositoryService.getObject(ShadowType.class, shadowRef.getOid(), null, result); + return shadow; + } + + +} diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java index 1be40939f4f..162cf61ee4a 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java @@ -113,6 +113,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationProvisioningScriptsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceObjectReferenceType; 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; @@ -359,7 +360,7 @@ public String addShadow(PrismObject shadow, OperationProvisioningScr RefinedObjectClassDefinition objectClassDefinition; try { - objectClassDefinition = determineObjectClassDefinition(shadow, resource); + objectClassDefinition = RefinedObjectClassDefinition.determineObjectClassDefinition(shadow, resource); applyAttributesDefinition(shadow, resource); shadowManager.setKindIfNecessary(shadow.asObjectable(), objectClassDefinition); accessChecker.checkAdd(resource, shadow, objectClassDefinition, parentResult); @@ -779,7 +780,7 @@ private SearchResultMetadata searchObjectsIterativeInternal(QName objectClassNam ObjectQuery attributeQuery = createAttributeQuery(query); final ConnectorInstance connector = getConnectorInstance(resourceType, parentResult); - + ResultHandler resultHandler = new ResultHandler() { @Override @@ -1385,7 +1386,7 @@ public ObjectClassComplexTypeDefinition applyAttributesDefinition(ObjectDelta delta, PrismObject shadow, ResourceType resource) throws SchemaException, ConfigurationException { - ObjectClassComplexTypeDefinition objectClassDefinition = determineObjectClassDefinition(shadow, resource); + ObjectClassComplexTypeDefinition objectClassDefinition = RefinedObjectClassDefinition.determineObjectClassDefinition(shadow, resource); return applyAttributesDefinition(delta, objectClassDefinition, resource); } @@ -1419,7 +1420,7 @@ private ObjectClassComplexTypeDefinition applyAttributesDefinition(ObjectDelta shadow, ResourceType resource) throws SchemaException, ConfigurationException { - RefinedObjectClassDefinition objectClassDefinition = determineObjectClassDefinition(shadow, resource); + RefinedObjectClassDefinition objectClassDefinition = RefinedObjectClassDefinition.determineObjectClassDefinition(shadow, resource); PrismContainer attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); if (attributesContainer != null) { @@ -1449,37 +1450,6 @@ public RefinedObjectClassDefinition applyAttributesDefinition( return objectClassDefinition; } - - private RefinedObjectClassDefinition determineObjectClassDefinition(PrismObject shadow, ResourceType resource) throws SchemaException, ConfigurationException { - ShadowType shadowType = shadow.asObjectable(); - RefinedResourceSchema refinedSchema = RefinedResourceSchema.getRefinedSchema(resource, prismContext); - if (refinedSchema == null) { - throw new ConfigurationException("No schema defined for "+resource); - } - - - RefinedObjectClassDefinition objectClassDefinition = null; - ShadowKindType kind = shadowType.getKind(); - String intent = shadowType.getIntent(); - QName objectClass = shadow.asObjectable().getObjectClass(); - if (kind != null) { - objectClassDefinition = refinedSchema.getRefinedDefinition(kind, intent); - } - if (objectClassDefinition == null) { - // Fallback to objectclass only - if (objectClass == null) { - throw new SchemaException("No kind nor objectclass definied in "+shadow); - } - objectClassDefinition = refinedSchema.findRefinedDefinitionByObjectClassQName(kind, objectClass); - } - - if (objectClassDefinition == null) { - throw new SchemaException("Definition for "+shadow+" not found (objectClass=" + PrettyPrinter.prettyPrint(objectClass) + - ", kind="+kind+", intent='"+intent+"') in schema of " + resource); - } - - return objectClassDefinition; - } private ObjectClassComplexTypeDefinition determineObjectClassDefinition( ResourceShadowDiscriminator discriminator, ResourceType resource) throws SchemaException { diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/api/ConnectorInstance.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/api/ConnectorInstance.java index 2685e3d9b43..ef7f738bdfb 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/api/ConnectorInstance.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/api/ConnectorInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2015 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,9 @@ import com.evolveum.midpoint.schema.SearchResultMetadata; import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; import com.evolveum.midpoint.schema.processor.ResourceAttribute; +import com.evolveum.midpoint.schema.processor.ResourceObjectIdentification; import com.evolveum.midpoint.schema.processor.ResourceSchema; +import com.evolveum.midpoint.schema.processor.SearchHierarchyConstraints; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; @@ -156,9 +158,10 @@ public Collection fetchCapabilities(OperationResult parentResult) throws * - nothing was fetched. * @throws SchemaException error converting object from native (connector) format */ - public PrismObject fetchObject( - Class type, ObjectClassComplexTypeDefinition objectClassDefinition, - Collection> identifiers, AttributesToReturn attributesToReturn, OperationResult parentResult) + public PrismObject fetchObject(Class type, + ResourceObjectIdentification resourceObjectIdentification, + AttributesToReturn attributesToReturn, + OperationResult parentResult) throws ObjectNotFoundException, CommunicationException, GenericFrameworkException, SchemaException, SecurityViolationException, ConfigurationException; @@ -178,10 +181,13 @@ public PrismObject fetchObject( * @throws CommunicationException * @throws SchemaException error converting object from the native (connector) format */ - public SearchResultMetadata search(ObjectClassComplexTypeDefinition objectClassDefinition, ObjectQuery query, - ResultHandler handler, AttributesToReturn attributesToReturn, - PagedSearchCapabilityType pagedSearchConfigurationType, - OperationResult parentResult) + public SearchResultMetadata search(ObjectClassComplexTypeDefinition objectClassDefinition, + ObjectQuery query, + ResultHandler handler, + AttributesToReturn attributesToReturn, + PagedSearchCapabilityType pagedSearchConfigurationType, + SearchHierarchyConstraints searchHierarchyConstraints, + OperationResult parentResult) throws CommunicationException, GenericFrameworkException, SchemaException; /** diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java index 00f11ffcd29..f690b585095 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/ucf/impl/ConnectorInstanceIcfImpl.java @@ -75,6 +75,7 @@ import org.identityconnectors.framework.common.objects.OperationOptions; import org.identityconnectors.framework.common.objects.OperationOptionsBuilder; import org.identityconnectors.framework.common.objects.OperationalAttributes; +import org.identityconnectors.framework.common.objects.QualifiedUid; import org.identityconnectors.framework.common.objects.ResultsHandler; import org.identityconnectors.framework.common.objects.ScriptContext; import org.identityconnectors.framework.common.objects.SearchResult; @@ -128,7 +129,9 @@ import com.evolveum.midpoint.schema.processor.ResourceAttributeContainer; import com.evolveum.midpoint.schema.processor.ResourceAttributeContainerDefinition; import com.evolveum.midpoint.schema.processor.ResourceAttributeDefinition; +import com.evolveum.midpoint.schema.processor.ResourceObjectIdentification; import com.evolveum.midpoint.schema.processor.ResourceSchema; +import com.evolveum.midpoint.schema.processor.SearchHierarchyConstraints; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.schema.util.ActivationUtil; @@ -907,11 +910,12 @@ private boolean shouldBeGenerated(List generateObjectClasses, @Override public PrismObject fetchObject(Class type, - ObjectClassComplexTypeDefinition objectClassDefinition, - Collection> identifiers, AttributesToReturn attributesToReturn, OperationResult parentResult) + ResourceObjectIdentification resourceObjectIdentification, AttributesToReturn attributesToReturn, OperationResult parentResult) throws ObjectNotFoundException, CommunicationException, GenericFrameworkException, SchemaException, SecurityViolationException, ConfigurationException { + Collection> identifiers = resourceObjectIdentification.getIdentifiers(); + ObjectClassComplexTypeDefinition objectClassDefinition = resourceObjectIdentification.getObjectClassDefinition(); // Result type for this operation OperationResult result = parentResult.createMinorSubresult(ConnectorInstance.class.getName() + ".fetchObject"); @@ -1863,9 +1867,13 @@ public void test(OperationResult parentResult) { } @Override - public SearchResultMetadata search(ObjectClassComplexTypeDefinition objectClassDefinition, final ObjectQuery query, - final ResultHandler handler, AttributesToReturn attributesToReturn, - PagedSearchCapabilityType pagedSearchCapabilityType, OperationResult parentResult) + public SearchResultMetadata search(ObjectClassComplexTypeDefinition objectClassDefinition, + final ObjectQuery query, + final ResultHandler handler, + AttributesToReturn attributesToReturn, + PagedSearchCapabilityType pagedSearchCapabilityType, + SearchHierarchyConstraints searchHierarchyConstraints, + OperationResult parentResult) throws CommunicationException, GenericFrameworkException, SchemaException { // Result type for this operation @@ -1959,6 +1967,16 @@ public boolean handle(ConnectorObject connectorObject) { String orderByIcfName = icfNameMapper.convertAttributeNameToIcf(orderBy, getSchemaNamespace()); optionsBuilder.setSortKeys(new SortKey(orderByIcfName, isAscending)); } + } + if (searchHierarchyConstraints != null) { + ResourceObjectIdentification baseContextIdentification = searchHierarchyConstraints.getBaseContext(); + // Only LDAP connector really supports base context. And this one will work better with + // DN. And DN is usually stored in icfs:name. This is ugly, but practical. It works around ConnId problems. + ResourceAttribute secondaryIdentifier = ShadowUtil.getSecondaryIdentifier(objectClassDefinition, baseContextIdentification.getIdentifiers()); + String secondaryIdentifierValue = secondaryIdentifier.getRealValue(String.class); + ObjectClass baseContextIcfObjectClass = icfNameMapper.objectClassToIcf(baseContextIdentification.getObjectClassDefinition(), getSchemaNamespace(), connectorType); + QualifiedUid containerQualifiedUid = new QualifiedUid(baseContextIcfObjectClass, new Uid(secondaryIdentifierValue)); + optionsBuilder.setContainer(containerQualifiedUid); } OperationOptions options = optionsBuilder.build(); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/ucf/TestUcfDummy.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/ucf/TestUcfDummy.java index e4e61c3680f..51e6d6ab6c2 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/ucf/TestUcfDummy.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/ucf/TestUcfDummy.java @@ -407,7 +407,7 @@ public boolean handle(PrismObject shadow) { OperationResult result = new OperationResult(this.getClass().getName() + ".testSearch"); // WHEN - cc.search(accountDefinition, new ObjectQuery(), handler, null, null, result); + cc.search(accountDefinition, new ObjectQuery(), handler, null, null, null, result); // THEN assertEquals("Unexpected number of search results", 1, searchResults.size()); diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/ucf/TestUcfOpenDj.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/ucf/TestUcfOpenDj.java index fbf14b4492e..efe6d85844b 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/ucf/TestUcfOpenDj.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/test/ucf/TestUcfOpenDj.java @@ -300,10 +300,11 @@ public void testAddDeleteObject() throws Exception { ObjectClassComplexTypeDefinition accountDefinition = resourceSchema.findDefaultObjectClassDefinition(ShadowKindType.ACCOUNT); cc.deleteObject(accountDefinition, null, identifiers, result); - + + ResourceObjectIdentification identification = new ResourceObjectIdentification(accountDefinition, identifiers); PrismObject resObj = null; try { - resObj = cc.fetchObject(ShadowType.class, accountDefinition, identifiers, null, + resObj = cc.fetchObject(ShadowType.class, identification, null, result); Assert.fail(); } catch (ObjectNotFoundException ex) { @@ -331,8 +332,8 @@ public void testChangeModifyObject() throws Exception { cc.modifyObject(accountDefinition, identifiers, changes, result); - PrismObject shadow = cc.fetchObject(ShadowType.class, accountDefinition, - identifiers, null, result); + ResourceObjectIdentification identification = new ResourceObjectIdentification(accountDefinition, identifiers); + PrismObject shadow = cc.fetchObject(ShadowType.class, identification, null, result); ResourceAttributeContainer resObj = ShadowUtil.getAttributesContainer(shadow); AssertJUnit.assertNull(resObj.findAttribute(new QName(ResourceTypeUtil.getResourceNamespace(resourceType), "givenName"))); @@ -604,11 +605,11 @@ public void testFetchObject() throws Exception { Collection> identifiers = resourceObject.getIdentifiers(); // Determine object class from the schema + ResourceObjectIdentification identification = new ResourceObjectIdentification(accountDefinition, identifiers); OperationResult result = new OperationResult(this.getClass().getName() + ".testFetchObject"); // WHEN - PrismObject ro = cc.fetchObject(ShadowType.class, accountDefinition, - identifiers, null, result); + PrismObject ro = cc.fetchObject(ShadowType.class, identification, null, result); // THEN @@ -628,7 +629,6 @@ public void testSearch() throws UcfException, SchemaException, CommunicationExce // Determine object class from the schema ResultHandler handler = new ResultHandler() { - @Override public boolean handle(PrismObject object) { System.out.println("Search: found: " + object); @@ -639,7 +639,7 @@ public boolean handle(PrismObject object) { OperationResult result = new OperationResult(this.getClass().getName() + ".testSearch"); // WHEN - cc.search(accountDefinition, new ObjectQuery(), handler, null, null, result); + cc.search(accountDefinition, new ObjectQuery(), handler, null, null, null, result); // THEN