Repository: syncope Updated Branches: refs/heads/master 5537d29e9 -> 72e6ceb06
http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java index 2568f45..4a203f9 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java @@ -156,6 +156,9 @@ abstract class AbstractAnyDataBinder { @Autowired protected ConnObjectUtils connObjectUtils; + @Autowired + protected MappingUtils mappingUtils; + protected void setRealm(final Any<?, ?, ?> any, final AnyPatch anyPatch) { if (anyPatch.getRealm() != null && StringUtils.isNotBlank(anyPatch.getRealm().getValue())) { Realm newRealm = realmDAO.find(anyPatch.getRealm().getValue()); @@ -231,11 +234,9 @@ abstract class AbstractAnyDataBinder { && (item.getPurpose() == MappingPurpose.PROPAGATION || item.getPurpose() == MappingPurpose.BOTH)) { - List<PlainAttrValue> values = MappingUtils.getIntValues( + List<PlainAttrValue> values = mappingUtils.getIntValues( provision, item, Collections.<Any<?, ?, ?>>singletonList(any), null); - if ((values == null || values.isEmpty()) - && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) { - + if (values.isEmpty() && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) { missingAttrNames.add(item.getIntAttrName()); } } @@ -360,8 +361,8 @@ abstract class AbstractAnyDataBinder { plainAttrDAO.delete(attr.getKey(), anyUtils.plainAttrClass()); for (ExternalResource resource : resources) { - for (MappingItem mapItem : MappingUtils.getMappingItems( - resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) { + for (MappingItem mapItem + : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) { if (schema.getKey().equals(mapItem.getIntAttrName()) && mapItem.getIntMappingType() == anyUtils.plainIntMappingType()) { @@ -410,8 +411,8 @@ abstract class AbstractAnyDataBinder { derAttrDAO.delete(attr); for (ExternalResource resource : resources) { - for (MappingItem mapItem : MappingUtils.getMappingItems( - resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) { + for (MappingItem mapItem + : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) { if (schema.getKey().equals(mapItem.getIntAttrName()) && mapItem.getIntMappingType() == anyUtils.derIntMappingType()) { @@ -704,7 +705,7 @@ abstract class AbstractAnyDataBinder { + " on resource '" + resource.getKey() + "'"); } - connObjectKeys.put(resource.getKey(), MappingUtils.getConnObjectKeyValue(any, provision)); + connObjectKeys.put(resource.getKey(), mappingUtils.getConnObjectKeyValue(any, provision)); } } http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java new file mode 100644 index 0000000..3810a87 --- /dev/null +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.syncope.core.provisioning.java.data; + +import java.util.List; +import org.apache.syncope.core.persistence.api.entity.PlainAttrValue; +import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer; + +/** + * Default (empty) implementation of {@link MappingItemTransformer}. + */ +public class DefaultMappingItemTransformer implements MappingItemTransformer { + + @Override + public List<PlainAttrValue> beforePropagation(final List<PlainAttrValue> values) { + return values; + } + + @Override + public List<Object> beforeSync(final List<Object> values) { + return values; + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java index 4ccc0c4..69a2e9d 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java @@ -22,13 +22,13 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.syncope.common.lib.types.AuditElements; import org.apache.syncope.common.lib.types.AuditElements.Result; -import org.apache.syncope.common.lib.types.MappingPurpose; import org.apache.syncope.common.lib.types.PropagationTaskExecStatus; import org.apache.syncope.common.lib.types.TraceLevel; import org.apache.syncope.core.persistence.api.dao.GroupDAO; @@ -148,6 +148,27 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask return result; } + /** + * Transform a + * <code>Collection</code> of {@link Attribute} instances into a {@link Map}. The key to each element in the map is + * the <i>name</i> of an + * <code>Attribute</code>. The value of each element in the map is the + * <code>Attribute</code> instance with that name. <br/> Different from the original because: <ul> <li>map keys are + * transformed toUpperCase()</li> <li>returned map is mutable</li> </ul> + * + * @param attributes set of attribute to transform to a map. + * @return a map of string and attribute. + * + * @see org.identityconnectors.framework.common.objects.AttributeUtil#toMap(java.util.Collection) + */ + private Map<String, Attribute> toMap(final Collection<? extends Attribute> attributes) { + Map<String, Attribute> map = new HashMap<>(); + for (Attribute attr : attributes) { + map.put(attr.getName().toUpperCase(), attr); + } + return map; + } + protected void createOrUpdate( final PropagationTask task, final ConnectorObject beforeObj, @@ -155,10 +176,10 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask final Set<String> propagationAttempted) { // set of attributes to be propagated - final Set<Attribute> attributes = new HashSet<>(task.getAttributes()); + Set<Attribute> attributes = new HashSet<>(task.getAttributes()); // check if there is any missing or null / empty mandatory attribute - List<Object> mandatoryAttrNames = new ArrayList<>(); + Set<Object> mandatoryAttrNames = new HashSet<>(); Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, task.getAttributes()); if (mandatoryMissing != null) { attributes.remove(mandatoryMissing); @@ -200,8 +221,8 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask // 2. check wether anything is actually needing to be propagated, i.e. if there is attribute // difference between beforeObj - just read above from the connector - and the values to be propagated - Map<String, Attribute> originalAttrMap = connObjectUtils.toMap(beforeObj.getAttributes()); - Map<String, Attribute> updateAttrMap = connObjectUtils.toMap(attributes); + Map<String, Attribute> originalAttrMap = toMap(beforeObj.getAttributes()); + Map<String, Attribute> updateAttrMap = toMap(attributes); // Only compare attribute from beforeObj that are also being updated Set<String> skipAttrNames = originalAttrMap.keySet(); @@ -527,7 +548,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask task.getOperation(), new ObjectClass(task.getObjectClassName()), new Uid(connObjectKey), - connector.getOperationOptions(MappingUtils.getMappingItems(provision, MappingPurpose.PROPAGATION))); + connector.getOperationOptions(MappingUtils.getPropagationMappingItems(provision))); } catch (TimeoutException toe) { LOG.debug("Request timeout", toe); throw toe; http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationActions.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationActions.java index 23726ed..157fdc1 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationActions.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationActions.java @@ -24,7 +24,7 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationActions; import org.identityconnectors.framework.common.objects.ConnectorObject; /** - * Default (empty) implementation of PropagationActions. + * Default (empty) implementation of {@link PropagationActions}. */ public abstract class DefaultPropagationActions implements PropagationActions { http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java index 7437241..22feb44 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java @@ -77,7 +77,7 @@ public class DefaultPropagationReporter implements PropagationReporter { for (PropagationTask propagationTask : tasks) { if (!containsPropagationStatusTO(propagationTask.getResource().getKey())) { - final PropagationStatus propagationStatusTO = new PropagationStatus(); + PropagationStatus propagationStatusTO = new PropagationStatus(); propagationStatusTO.setResource(propagationTask.getResource().getKey()); propagationStatusTO.setStatus(PropagationTaskExecStatus.FAILURE); propagationStatusTO.setFailureReason( http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java index b8bc838..ebf9c99 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java @@ -34,7 +34,6 @@ import org.apache.syncope.common.lib.patch.StringPatchItem; import org.apache.syncope.common.lib.patch.UserPatch; import org.apache.syncope.common.lib.to.AttrTO; import org.apache.syncope.common.lib.types.AnyTypeKind; -import org.apache.syncope.common.lib.types.MappingPurpose; import org.apache.syncope.common.lib.types.PropagationByResource; import org.apache.syncope.common.lib.types.ResourceOperation; import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO; @@ -106,6 +105,9 @@ public class PropagationManagerImpl implements PropagationManager { @Autowired protected VirAttrHandler virAttrHandler; + @Autowired + protected MappingUtils mappingUtils; + protected Any<?, ?, ?> find(final AnyTypeKind kind, final Long key) { AnyDAO<? extends Any<?, ?, ?>> dao; switch (kind) { @@ -367,7 +369,7 @@ public class PropagationManagerImpl implements PropagationManager { } else if (provision == null) { LOG.error("No provision specified on resource {} for type {}, ignoring...", resource, any.getType()); - } else if (MappingUtils.getMappingItems(provision, MappingPurpose.PROPAGATION).isEmpty()) { + } else if (MappingUtils.getPropagationMappingItems(provision).isEmpty()) { LOG.warn("Requesting propagation for {} but no propagation mapping provided for {}", any.getType(), resource); } else { @@ -382,7 +384,7 @@ public class PropagationManagerImpl implements PropagationManager { task.setOperation(operation); task.setOldConnObjectKey(propByRes.getOldConnObjectKey(resource.getKey())); - Pair<String, Set<Attribute>> preparedAttrs = MappingUtils.prepareAttrs( + Pair<String, Set<Attribute>> preparedAttrs = mappingUtils.prepareAttrs( any, password, changePwd, vAttrs, enable, provision); task.setConnObjectKey(preparedAttrs.getKey()); @@ -390,7 +392,7 @@ public class PropagationManagerImpl implements PropagationManager { // if so, add special attributes that will be evaluated by PropagationTaskExecutor List<String> mandatoryMissing = new ArrayList<>(); List<String> mandatoryNullOrEmpty = new ArrayList<>(); - for (MappingItem item : MappingUtils.getMappingItems(provision, MappingPurpose.PROPAGATION)) { + for (MappingItem item : MappingUtils.getPropagationMappingItems(provision)) { if (!item.isConnObjectKey() && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) { http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java index 8aa37d3..94936eb 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java @@ -58,12 +58,16 @@ import org.identityconnectors.framework.common.objects.ConnectorObject; import org.identityconnectors.framework.common.objects.ObjectClass; import org.identityconnectors.framework.common.objects.Uid; import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHandler<PushTask, PushActions> implements SyncopePushResultHandler { + @Autowired + protected MappingUtils mappingUtils; + protected abstract String getName(Any<?, ?, ?> any); protected void deprovision(final Any<?, ?, ?> any) { @@ -195,7 +199,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan // Try to read remote object BEFORE any actual operation Provision provision = profile.getTask().getResource().getProvision(any.getType()); - String connObjecKey = MappingUtils.getConnObjectKeyValue(any, provision); + String connObjecKey = mappingUtils.getConnObjectKeyValue(any, provision); ConnectorObject beforeObj = getRemoteObject(connObjecKey, provision.getObjectClass()); http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java index 30d2879..2ca7eaa 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java @@ -201,7 +201,7 @@ public abstract class AbstractSyncResultHandler extends AbstractSyncopeResultHan create(anyTO, actionedDelta, UnmatchingRule.toEventName(UnmatchingRule.PROVISION), result); } - return Collections.<ProvisioningResult>singletonList(result); + return Collections.singletonList(result); } private void create( http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java index 1af195e..1ed0d2c 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PlainAttrsSyncCorrelationRule.java @@ -18,17 +18,19 @@ */ package org.apache.syncope.core.provisioning.java.sync; +import static org.apache.syncope.core.misc.MappingUtils.getMappingItemTransformers; + import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.syncope.common.lib.types.MappingPurpose; import org.apache.syncope.core.misc.MappingUtils; import org.apache.syncope.core.persistence.api.dao.search.AnyCond; import org.apache.syncope.core.persistence.api.dao.search.AttributeCond; import org.apache.syncope.core.persistence.api.dao.search.SearchCond; import org.apache.syncope.core.persistence.api.entity.resource.MappingItem; import org.apache.syncope.core.persistence.api.entity.resource.Provision; +import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer; import org.apache.syncope.core.provisioning.api.sync.SyncCorrelationRule; import org.identityconnectors.framework.common.objects.Attribute; import org.identityconnectors.framework.common.objects.ConnectorObject; @@ -46,41 +48,44 @@ public class PlainAttrsSyncCorrelationRule implements SyncCorrelationRule { @Override public SearchCond getSearchCond(final ConnectorObject connObj) { - // search for external attribute's name/value of each specified name - Map<String, Attribute> extValues = new HashMap<>(); - - for (MappingItem item : MappingUtils.getMappingItems(provision, MappingPurpose.SYNCHRONIZATION)) { - extValues.put(item.getIntAttrName(), connObj.getAttributeByName(item.getExtAttrName())); + Map<String, MappingItem> mappingItems = new HashMap<>(); + for (MappingItem item : MappingUtils.getSyncMappingItems(provision)) { + mappingItems.put(item.getIntAttrName(), item); } - // search for user/group by attribute(s) specified in the policy + // search for anys by attribute(s) specified in the policy SearchCond searchCond = null; for (String schema : plainSchemaNames) { - Attribute value = extValues.get(schema); - - if (value == null) { + Attribute attr = mappingItems.get(schema) == null + ? null + : connObj.getAttributeByName(mappingItems.get(schema).getExtAttrName()); + if (attr == null) { throw new IllegalArgumentException( "Connector object does not contains the attributes to perform the search: " + schema); } + List<Object> values = attr.getValue(); + for (MappingItemTransformer transformer : getMappingItemTransformers(mappingItems.get(schema))) { + values = transformer.beforeSync(values); + } + AttributeCond.Type type; String expression = null; - if (value.getValue() == null || value.getValue().isEmpty() - || (value.getValue().size() == 1 && value.getValue().get(0) == null)) { - + if (values == null || values.isEmpty() || (values.size() == 1 && values.get(0) == null)) { type = AttributeCond.Type.ISNULL; } else { type = AttributeCond.Type.EQ; - expression = value.getValue().size() > 1 - ? value.getValue().toString() - : value.getValue().get(0).toString(); + expression = values.size() > 1 + ? values.toString() + : values.get(0).toString(); } SearchCond nodeCond; - // users: just id or username can be selected to be used - // groups: just id or name can be selected to be used + // users: just key or username can be selected + // groups: just key or name can be selected + // any objects: just key can be selected if ("key".equalsIgnoreCase(schema) || "username".equalsIgnoreCase(schema) || "name".equalsIgnoreCase(schema)) { http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java index 6fe699b..0c01254 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/SyncUtils.java @@ -24,7 +24,6 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.common.lib.SyncopeConstants; import org.apache.syncope.common.lib.types.AnyTypeKind; -import org.apache.syncope.common.lib.types.MappingPurpose; import org.apache.syncope.common.lib.policy.SyncPolicySpec; import org.apache.syncope.core.misc.MappingUtils; import org.apache.syncope.core.misc.serialization.POJOHelper; @@ -49,6 +48,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.Provision; import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask; import org.apache.syncope.core.persistence.api.entity.user.User; import org.apache.syncope.core.provisioning.api.Connector; +import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer; import org.apache.syncope.core.provisioning.api.sync.SyncCorrelationRule; import org.identityconnectors.framework.common.objects.Attribute; import org.identityconnectors.framework.common.objects.AttributeUtil; @@ -128,7 +128,7 @@ public class SyncUtils { return found.add(obj); } }, - connector.getOperationOptions(MappingUtils.getMappingItems(provision, MappingPurpose.SYNCHRONIZATION))); + connector.getOperationOptions(MappingUtils.getSyncMappingItems(provision))); if (found.isEmpty()) { LOG.debug("No {} found on {} with __NAME__ {}", provision.getObjectClass(), resource, name); @@ -172,6 +172,15 @@ public class SyncUtils { List<Long> result = new ArrayList<>(); MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision); + + String transfUid = uid; + for (MappingItemTransformer transformer : MappingUtils.getMappingItemTransformers(connObjectKeyItem)) { + List<Object> output = transformer.beforeSync(Collections.<Object>singletonList(transfUid)); + if (output != null && !output.isEmpty()) { + transfUid = output.get(0).toString(); + } + } + switch (connObjectKeyItem.getIntMappingType()) { case UserPlainSchema: case GroupPlainSchema: @@ -180,13 +189,13 @@ public class SyncUtils { PlainSchema schema = plainSchemaDAO.find(connObjectKeyItem.getIntAttrName()); if (schema == null) { - value.setStringValue(uid); + value.setStringValue(transfUid); } else { try { - value.parseValue(schema, uid); + value.parseValue(schema, transfUid); } catch (ParsingValidationException e) { - LOG.error("While parsing provided __UID__ {}", uid, e); - value.setStringValue(uid); + LOG.error("While parsing provided __UID__ {}", transfUid, e); + value.setStringValue(transfUid); } } @@ -200,7 +209,7 @@ public class SyncUtils { case UserDerivedSchema: case GroupDerivedSchema: case AnyObjectDerivedSchema: - anys = getAnyDAO(connObjectKeyItem).findByDerAttrValue(connObjectKeyItem.getIntAttrName(), uid); + anys = getAnyDAO(connObjectKeyItem).findByDerAttrValue(connObjectKeyItem.getIntAttrName(), transfUid); for (Any<?, ?, ?> any : anys) { result.add(any.getKey()); } @@ -209,21 +218,21 @@ public class SyncUtils { case UserKey: case GroupKey: case AnyObjectKey: - Any<?, ?, ?> any = getAnyDAO(connObjectKeyItem).find(Long.parseLong(uid)); + Any<?, ?, ?> any = getAnyDAO(connObjectKeyItem).find(Long.parseLong(transfUid)); if (any != null) { result.add(any.getKey()); } break; case Username: - User user = userDAO.find(uid); + User user = userDAO.find(transfUid); if (user != null) { result.add(user.getKey()); } break; case GroupName: - Group group = groupDAO.find(uid); + Group group = groupDAO.find(transfUid); if (group != null) { result.add(group.getKey()); } @@ -240,12 +249,12 @@ public class SyncUtils { final ConnectorObject connObj, final SyncCorrelationRule rule, final AnyTypeKind type) { List<Long> result = new ArrayList<>(); - - List<Any<?, ?, ?>> anys = searchDAO.search( + for (Any<?, ?, ?> any : searchDAO.search( SyncopeConstants.FULL_ADMIN_REALMS, rule.getSearchCond(connObj), - Collections.<OrderByClause>emptyList(), type); - for (Any<?, ?, ?> any : anys) { + Collections.<OrderByClause>emptyList(), + type)) { + result.add(any.getKey()); } http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java new file mode 100644 index 0000000..c620541 --- /dev/null +++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.syncope.fit.core.reference; + +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.core.persistence.api.entity.PlainAttrValue; +import org.apache.syncope.core.provisioning.java.data.DefaultMappingItemTransformer; + +public class PrefixMappingItemTransformer extends DefaultMappingItemTransformer { + + public static final String PREFIX = "PREFIX_"; + + @Override + public List<PlainAttrValue> beforePropagation(final List<PlainAttrValue> values) { + if (values == null || values.isEmpty() || values.get(0).getStringValue() == null) { + return super.beforePropagation(values); + } else { + String value = values.get(0).getStringValue(); + values.get(0).setStringValue(PREFIX + value); + + return values; + } + } + + @Override + public List<Object> beforeSync(final List<Object> values) { + if (values == null || values.isEmpty() || values.get(0) == null) { + return super.beforeSync(values); + } else { + List<Object> newValues = new ArrayList<>(values); + newValues.set(0, StringUtils.substringAfter(values.get(0).toString(), PREFIX)); + + return newValues; + } + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java index eaff578..75049da 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/SyncTaskITCase.java @@ -32,6 +32,7 @@ import java.util.Set; import javax.ws.rs.core.Response; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.Predicate; +import org.apache.commons.lang3.SerializationUtils; import org.apache.syncope.client.lib.SyncopeClient; import org.apache.syncope.common.lib.SyncopeClientException; import org.apache.syncope.common.lib.SyncopeConstants; @@ -49,6 +50,7 @@ import org.apache.syncope.common.lib.to.ResourceTO; import org.apache.syncope.common.lib.to.GroupTO; import org.apache.syncope.common.lib.to.ProvisionTO; import org.apache.syncope.common.lib.policy.SyncPolicyTO; +import org.apache.syncope.common.lib.to.MappingItemTO; import org.apache.syncope.common.lib.to.SyncTaskTO; import org.apache.syncope.common.lib.to.TaskExecTO; import org.apache.syncope.common.lib.to.UserTO; @@ -356,47 +358,78 @@ public class SyncTaskITCase extends AbstractTaskITCase { @Test public void reconcileFromScriptedSQL() { - // 0. reset sync token + // 0. reset sync token and set MappingItemTransformer ResourceTO resource = resourceService.read(RESOURCE_NAME_DBSCRIPTED); + ResourceTO originalResource = SerializationUtils.clone(resource); ProvisionTO provision = resource.getProvision("PRINTER"); assertNotNull(provision); - provision.setSyncToken(null); - resourceService.update(resource); - - // 1. create printer on external resource - AnyObjectTO anyObjectTO = AnyObjectITCase.getSampleTO("sync"); - anyObjectTO = createAnyObject(anyObjectTO); - assertNotNull(anyObjectTO); - - // 2. unlink any existing printer and delete from Syncope (printer is now only on external resource) - PagedResult<AnyObjectTO> matchingPrinters = anyObjectService.search( - SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM). - fiql(SyncopeClient.getAnyObjectSearchConditionBuilder().type("PRINTER").and(). - is("location").equalTo("sync*").query()).build()); - assertTrue(matchingPrinters.getSize() > 0); - for (AnyObjectTO printer : matchingPrinters.getResult()) { - DeassociationPatch deassociationPatch = new DeassociationPatch(); - deassociationPatch.setKey(printer.getKey()); - deassociationPatch.setAction(ResourceDeassociationAction.UNLINK); - deassociationPatch.getResources().add(RESOURCE_NAME_DBSCRIPTED); - anyObjectService.deassociate(deassociationPatch); - anyObjectService.delete(printer.getKey()); - } + try { + provision.setSyncToken(null); + + MappingItemTO mappingItem = CollectionUtils.find( + provision.getMapping().getItems(), new Predicate<MappingItemTO>() { + + @Override + public boolean evaluate(final MappingItemTO object) { + return "location".equals(object.getIntAttrName()); + } + }); + assertNotNull(mappingItem); + mappingItem.getMappingItemTransformerClassNames().clear(); + mappingItem.getMappingItemTransformerClassNames().add(PrefixMappingItemTransformer.class.getName()); + + resourceService.update(resource); + + // 1. create printer on external resource + AnyObjectTO anyObjectTO = AnyObjectITCase.getSampleTO("sync"); + String originalLocation = anyObjectTO.getPlainAttrMap().get("location").getValues().get(0); + assertFalse(originalLocation.startsWith(PrefixMappingItemTransformer.PREFIX)); + + anyObjectTO = createAnyObject(anyObjectTO); + assertNotNull(anyObjectTO); + + // 2. verify that PrefixMappingItemTransformer was applied during propagation + // (location starts with given prefix on external resource) + ConnObjectTO connObjectTO = resourceService. + readConnObject(RESOURCE_NAME_DBSCRIPTED, anyObjectTO.getType(), anyObjectTO.getKey()); + assertFalse(anyObjectTO.getPlainAttrMap().get("location").getValues().get(0). + startsWith(PrefixMappingItemTransformer.PREFIX)); + assertTrue(connObjectTO.getPlainAttrMap().get("location").getValues().get(0). + startsWith(PrefixMappingItemTransformer.PREFIX)); + + // 3. unlink any existing printer and delete from Syncope (printer is now only on external resource) + PagedResult<AnyObjectTO> matchingPrinters = anyObjectService.search( + SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM). + fiql(SyncopeClient.getAnyObjectSearchConditionBuilder().type("PRINTER").and(). + is("location").equalTo("sync*").query()).build()); + assertTrue(matchingPrinters.getSize() > 0); + for (AnyObjectTO printer : matchingPrinters.getResult()) { + DeassociationPatch deassociationPatch = new DeassociationPatch(); + deassociationPatch.setKey(printer.getKey()); + deassociationPatch.setAction(ResourceDeassociationAction.UNLINK); + deassociationPatch.getResources().add(RESOURCE_NAME_DBSCRIPTED); + anyObjectService.deassociate(deassociationPatch); + anyObjectService.delete(printer.getKey()); + } - // 3. synchronize - execProvisioningTask(taskService, 28L, 50, false); + // 4. synchronize + execProvisioningTask(taskService, 28L, 50, false); - // 4. verify that printer was re-created in Syncope - matchingPrinters = anyObjectService.search( - SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM). - fiql(SyncopeClient.getAnyObjectSearchConditionBuilder().type("PRINTER").and(). - is("location").equalTo("sync*").query()).build()); - assertTrue(matchingPrinters.getSize() > 0); + // 5. verify that printer was re-created in Syncope (implies that location does not start with given prefix, + // hence PrefixMappingItemTransformer was applied during sync) + matchingPrinters = anyObjectService.search( + SyncopeClient.getAnySearchQueryBuilder().realm(SyncopeConstants.ROOT_REALM). + fiql(SyncopeClient.getAnyObjectSearchConditionBuilder().type("PRINTER").and(). + is("location").equalTo("sync*").query()).build()); + assertTrue(matchingPrinters.getSize() > 0); - // 5. verify that synctoken was updated - assertNotNull( - resourceService.read(RESOURCE_NAME_DBSCRIPTED).getProvision(anyObjectTO.getType()).getSyncToken()); + // 6. verify that synctoken was updated + assertNotNull( + resourceService.read(RESOURCE_NAME_DBSCRIPTED).getProvision(anyObjectTO.getType()).getSyncToken()); + } finally { + resourceService.update(originalResource); + } } @Test
