http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java index 3d60089..5763449 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java @@ -19,7 +19,6 @@ package org.apache.syncope.core.provisioning.java; import org.apache.syncope.core.provisioning.api.VirAttrHandler; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -27,26 +26,12 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.collections4.Predicate; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.syncope.common.lib.patch.AttrPatch; -import org.apache.syncope.common.lib.to.AttrTO; -import org.apache.syncope.common.lib.types.AnyTypeKind; -import org.apache.syncope.common.lib.types.IntMappingType; -import org.apache.syncope.common.lib.types.PropagationByResource; -import org.apache.syncope.common.lib.types.ResourceOperation; import org.apache.syncope.core.misc.MappingUtils; import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO; -import org.apache.syncope.core.persistence.api.dao.GroupDAO; import org.apache.syncope.core.persistence.api.dao.UserDAO; -import org.apache.syncope.core.persistence.api.dao.VirAttrDAO; -import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO; import org.apache.syncope.core.persistence.api.entity.Any; -import org.apache.syncope.core.persistence.api.entity.AnyType; -import org.apache.syncope.core.persistence.api.entity.AnyUtils; -import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; -import org.apache.syncope.core.persistence.api.entity.VirAttr; import org.apache.syncope.core.persistence.api.entity.VirSchema; import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject; import org.apache.syncope.core.persistence.api.entity.group.Group; @@ -68,30 +53,17 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Component -@Transactional(rollbackFor = { Throwable.class }) public class VirAttrHandlerImpl implements VirAttrHandler { private static final Logger LOG = LoggerFactory.getLogger(VirAttrHandler.class); @Autowired - private VirSchemaDAO virSchemaDAO; - - @Autowired - private VirAttrDAO virAttrDAO; - - @Autowired private AnyObjectDAO anyObjectDAO; @Autowired private UserDAO userDAO; @Autowired - private GroupDAO groupDAO; - - @Autowired - private AnyUtilsFactory anyUtilsFactory; - - @Autowired private ConnectorFactory connFactory; /** @@ -103,290 +75,102 @@ public class VirAttrHandlerImpl implements VirAttrHandler { @Autowired private MappingUtils mappingUtils; - @Override - public VirSchema getVirSchema(final String virSchemaName) { - VirSchema virtualSchema = null; - if (StringUtils.isNotBlank(virSchemaName)) { - virtualSchema = virSchemaDAO.find(virSchemaName); - - if (virtualSchema == null) { - LOG.debug("Ignoring invalid virtual schema {}", virSchemaName); - } + private Map<VirSchema, List<String>> getValues(final Any<?, ?> any, final Set<VirSchema> schemas) { + Collection<? extends ExternalResource> ownedResources; + if (any instanceof User) { + ownedResources = userDAO.findAllResources((User) any); + } else if (any instanceof AnyObject) { + ownedResources = anyObjectDAO.findAllResources((AnyObject) any); + } else { + ownedResources = ((Group) any).getResources(); } - return virtualSchema; - } - - @Override - public void updateOnResourcesIfMappingMatches(final Any<?, ?, ?> any, final String schemaKey, - final Iterable<? extends ExternalResource> resources, final IntMappingType mappingType, - final PropagationByResource propByRes) { + Map<VirSchema, List<String>> result = new HashMap<>(); - for (ExternalResource resource : resources) { - for (MappingItem mapItem - : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) { + Map<Provision, Set<VirSchema>> toRead = new HashMap<>(); - if (schemaKey.equals(mapItem.getIntAttrName()) && mapItem.getIntMappingType() == mappingType) { - propByRes.add(ResourceOperation.UPDATE, resource.getKey()); - } - } - } - } - - private Iterable<? extends ExternalResource> getAllResources(final Any<?, ?, ?> any) { - return any instanceof User - ? userDAO.findAllResources((User) any) - : any instanceof AnyObject - ? anyObjectDAO.findAllResources((AnyObject) any) - : any instanceof Group - ? ((Group) any).getResources() - : Collections.<ExternalResource>emptySet(); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public void createVirtual(final Any any, final Collection<AttrTO> vAttrs) { - AnyUtils anyUtils = anyUtilsFactory.getInstance(any); + for (VirSchema schema : schemas) { + if (ownedResources.contains(schema.getProvision().getResource())) { + VirAttrCacheValue virAttrCacheValue = + virAttrCache.get(any.getType().getKey(), any.getKey(), schema.getKey()); - for (AttrTO attrTO : vAttrs) { - VirAttr virAttr = any.getVirAttr(attrTO.getSchema()); - if (virAttr == null) { - VirSchema virSchema = getVirSchema(attrTO.getSchema()); - if (virSchema != null) { - virAttr = anyUtils.newVirAttr(); - virAttr.setSchema(virSchema); - if (virAttr.getSchema() == null) { - LOG.debug("Ignoring {} because no valid schema was found", attrTO); - } else { - virAttr.setOwner(any); - any.add(virAttr); - virAttr.getValues().clear(); - virAttr.getValues().addAll(attrTO.getValues()); + if (virAttrCache.isValidEntry(virAttrCacheValue)) { + LOG.debug("Values for {} found in cache: {}", schema, virAttrCacheValue); + result.put(schema, virAttrCacheValue.getValues()); + } else { + Set<VirSchema> schemasToRead = toRead.get(schema.getProvision()); + if (schemasToRead == null) { + schemasToRead = new HashSet<>(); + toRead.put(schema.getProvision(), schemasToRead); } + schemasToRead.add(schema); } } else { - virAttr.getValues().clear(); - virAttr.getValues().addAll(attrTO.getValues()); + LOG.debug("Not considering {} since {} is not assigned to {}", + schema, any, schema.getProvision().getResource()); } } - } - - private Any<?, ?, ?> find(final Long key, final AnyTypeKind anyTypeKind) { - Any<?, ?, ?> result; - - switch (anyTypeKind) { - case USER: - result = userDAO.authFind(key); - break; - - case GROUP: - result = groupDAO.authFind(key); - break; - - case ANY_OBJECT: - default: - result = anyObjectDAO.authFind(key); - } - - return result; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public PropagationByResource updateVirtual(final Any any, final Collection<AttrPatch> vAttrs) { - AnyUtils anyUtils = anyUtilsFactory.getInstance(any); - - PropagationByResource propByRes = new PropagationByResource(); - - Iterable<? extends ExternalResource> externalResources = getAllResources(any); - - for (AttrPatch patch : vAttrs) { - VirSchema virSchema = getVirSchema(patch.getAttrTO().getSchema()); - if (virSchema != null) { - VirAttr virAttr = any.getVirAttr(virSchema.getKey()); - switch (patch.getOperation()) { - case ADD_REPLACE: - if (virAttr == null) { - virAttr = anyUtils.newVirAttr(); - virAttr.setOwner(any); - virAttr.setSchema(virSchema); - - any.add(virAttr); - } - - updateOnResourcesIfMappingMatches( - any, virSchema.getKey(), externalResources, anyUtils.virIntMappingType(), propByRes); - - if (!virAttr.getValues().equals(patch.getAttrTO().getValues())) { - virAttr.getValues().clear(); - virAttr.getValues().addAll(patch.getAttrTO().getValues()); - } - break; - - case DELETE: - default: - if (virAttr == null) { - LOG.debug("No virtual attribute found for schema {}", virSchema.getKey()); - } else { - any.remove(virAttr); - virAttrDAO.delete(virAttr); - } - - for (ExternalResource resource : externalResources) { - for (MappingItem mapItem - : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) { - if (virSchema.getKey().equals(mapItem.getIntAttrName()) - && mapItem.getIntMappingType() == anyUtils.virIntMappingType()) { + for (Map.Entry<Provision, Set<VirSchema>> entry : toRead.entrySet()) { + LOG.debug("About to read from {}: {}", entry.getKey(), entry.getValue()); - propByRes.add(ResourceOperation.UPDATE, resource.getKey()); - - // Using virtual attribute as ConnObjectKey must be avoided - if (mapItem.isConnObjectKey() - && virAttr != null && !virAttr.getValues().isEmpty()) { - - propByRes.addOldConnObjectKey( - resource.getKey(), virAttr.getValues().get(0).toString()); - } - } - } - } + String connObjectKey = MappingUtils.getConnObjectKeyItem(entry.getKey()) == null + ? null + : mappingUtils.getConnObjectKeyValue(any, entry.getKey()); + if (StringUtils.isBlank(connObjectKey)) { + LOG.error("No ConnObjectKey found for {}, ignoring...", entry.getKey()); + } else { + Set<MappingItem> linkingMappingItems = new HashSet<>(); + for (VirSchema schema : entry.getValue()) { + linkingMappingItems.add(schema.asLinkingMappingItem()); } - } - } - - return propByRes; - } - - @Transactional - @Override - public PropagationByResource updateVirtual( - final Long key, final AnyTypeKind anyTypeKind, final Collection<AttrPatch> vAttrs) { - - return updateVirtual(find(key, anyTypeKind), vAttrs); - } - - @Override - public void retrieveVirAttrValues(final Any<?, ?, ?> any) { - IntMappingType type = any.getType().getKind() == AnyTypeKind.USER - ? IntMappingType.UserVirtualSchema - : any.getType().getKind() == AnyTypeKind.GROUP - ? IntMappingType.GroupVirtualSchema - : IntMappingType.AnyObjectVirtualSchema; - - Map<String, ConnectorObject> resources = new HashMap<>(); - - // ----------------------- - // Retrieve virtual attribute values if and only if they have not been retrieved yet - // ----------------------- - for (VirAttr<?> virAttr : any.getVirAttrs()) { - // reset value set - if (virAttr.getValues().isEmpty()) { - retrieveVirAttrValue(any, virAttr, type, resources); - } - } - // ----------------------- - } - - private void retrieveVirAttrValue( - final Any<?, ?, ?> any, - final VirAttr<?> virAttr, - final IntMappingType type, - final Map<String, ConnectorObject> externalResources) { - - String schemaName = virAttr.getSchema().getKey(); - VirAttrCacheValue virAttrCacheValue = virAttrCache.get(any.getType().getKey(), any.getKey(), schemaName); - - LOG.debug("Retrieve values for virtual attribute {} ({})", schemaName, type); - - if (virAttrCache.isValidEntry(virAttrCacheValue)) { - // cached ... - LOG.debug("Values found in cache {}", virAttrCacheValue); - virAttr.getValues().clear(); - virAttr.getValues().addAll(new ArrayList<>(virAttrCacheValue.getValues())); - } else { - // not cached ... - LOG.debug("Need one or more remote connections"); - - VirAttrCacheValue toBeCached = new VirAttrCacheValue(); - - for (ExternalResource resource : getTargetResources(virAttr, type, any.getType())) { - Provision provision = resource.getProvision(any.getType()); - LOG.debug("Search values into {},{}", resource, provision); + Connector connector = connFactory.getConnector(entry.getKey().getResource()); try { - List<MappingItem> mapItems = MappingUtils.getBothMappingItems(provision); + ConnectorObject connectorObject = connector.getObject( + entry.getKey().getObjectClass(), + new Uid(connObjectKey), + connector.getOperationOptions(linkingMappingItems.iterator())); - ConnectorObject connectorObject; - if (externalResources.containsKey(resource.getKey())) { - connectorObject = externalResources.get(resource.getKey()); + if (connectorObject == null) { + LOG.debug("No read from {} about {}", entry.getKey(), connObjectKey); } else { - LOG.debug("Perform connection to {}", resource.getKey()); - String connObjectKey = MappingUtils.getConnObjectKeyItem(provision) == null - ? null - : mappingUtils.getConnObjectKeyValue(any, provision); - - if (StringUtils.isBlank(connObjectKey)) { - throw new IllegalArgumentException("No ConnObjectKey found for " + resource.getKey()); - } - - Connector connector = connFactory.getConnector(resource); - connectorObject = connector.getObject( - provision.getObjectClass(), - new Uid(connObjectKey), - connector.getOperationOptions(MappingUtils.getMatchingMappingItems(mapItems, type))); - externalResources.put(resource.getKey(), connectorObject); - } - - if (connectorObject != null) { - // the same virtual attribute could be mapped with one or more external attributes - for (MappingItem mapItem : MappingUtils.getMatchingMappingItems(mapItems, schemaName, type)) { - Attribute attr = connectorObject.getAttributeByName(mapItem.getExtAttrName()); - if (attr != null && attr.getValue() != null) { - for (Object obj : attr.getValue()) { - if (obj != null) { - virAttr.getValues().add(obj.toString()); - } - } + for (VirSchema schema : entry.getValue()) { + Attribute attr = connectorObject.getAttributeByName(schema.getExtAttrName()); + if (attr != null) { + VirAttrCacheValue virAttrCacheValue = new VirAttrCacheValue(); + virAttrCacheValue.setValues(attr.getValue()); + virAttrCache.put(any.getType().getKey(), any.getKey(), schema.getKey(), + virAttrCacheValue); + LOG.debug("Values for {} set in cache: {}", schema, virAttrCacheValue); + + result.put(schema, virAttrCacheValue.getValues()); } } - - toBeCached.setResourceValues(resource.getKey(), new HashSet<>(virAttr.getValues())); - - LOG.debug("Retrieved values {}", virAttr.getValues()); } } catch (Exception e) { - LOG.error("Error reading connector object from {}", resource.getKey(), e); - - if (virAttrCacheValue != null) { - toBeCached.forceExpiring(); - LOG.debug("Search for a cached value (even expired!) ..."); - final Set<String> cachedValues = virAttrCacheValue.getValues(resource.getKey()); - if (cachedValues != null) { - LOG.debug("Use cached value {}", cachedValues); - virAttr.getValues().addAll(cachedValues); - toBeCached.setResourceValues(resource.getKey(), new HashSet<>(cachedValues)); - } - } + LOG.error("Error reading from {}", entry.getKey(), e); } } - - virAttrCache.put(any.getType().getKey(), any.getKey(), schemaName, toBeCached); } + + return result; } - private Collection<ExternalResource> getTargetResources( - final VirAttr<?> attr, final IntMappingType type, final AnyType anyType) { + @Transactional(readOnly = true) + @Override + public List<String> getValues(final Any<?, ?> any, final VirSchema schema) { + if (!any.getAllowedVirSchemas().contains(schema)) { + LOG.debug("{} not allowed for {}", schema, any); + return Collections.emptyList(); + } - return CollectionUtils.select(getAllResources(attr.getOwner()), new Predicate<ExternalResource>() { + return ListUtils.emptyIfNull(getValues(any, Collections.singleton(schema)).get(schema)); + } - @Override - public boolean evaluate(final ExternalResource resource) { - return resource.getProvision(anyType) != null - && !MappingUtils.getMatchingMappingItems( - MappingUtils.getBothMappingItems(resource.getProvision(anyType)), - attr.getSchema().getKey(), type).isEmpty(); - } - }); + @Transactional(readOnly = true) + @Override + public Map<VirSchema, List<String>> getValues(final Any<?, ?> any) { + return getValues(any, any.getAllowedVirSchemas()); } }
http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/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 4a203f9..93a0b31 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 @@ -42,6 +42,7 @@ import org.apache.syncope.common.lib.to.RelationshipTO; import org.apache.syncope.common.lib.types.ClientExceptionType; import org.apache.syncope.common.lib.types.IntMappingType; import org.apache.syncope.common.lib.types.MappingPurpose; +import org.apache.syncope.common.lib.types.PatchOperation; import org.apache.syncope.common.lib.types.ResourceOperation; import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException; import org.apache.syncope.core.persistence.api.dao.DerAttrDAO; @@ -53,7 +54,6 @@ import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO; import org.apache.syncope.core.persistence.api.dao.PolicyDAO; import org.apache.syncope.core.persistence.api.dao.GroupDAO; import org.apache.syncope.core.persistence.api.dao.UserDAO; -import org.apache.syncope.core.persistence.api.dao.VirAttrDAO; import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO; import org.apache.syncope.core.persistence.api.entity.DerAttr; import org.apache.syncope.core.persistence.api.entity.DerSchema; @@ -61,8 +61,6 @@ import org.apache.syncope.core.persistence.api.entity.EntityFactory; import org.apache.syncope.core.persistence.api.entity.PlainAttr; import org.apache.syncope.core.persistence.api.entity.PlainAttrValue; import org.apache.syncope.core.persistence.api.entity.PlainSchema; -import org.apache.syncope.core.persistence.api.entity.VirAttr; -import org.apache.syncope.core.persistence.api.entity.VirSchema; import org.apache.syncope.core.persistence.api.entity.group.Group; import org.apache.syncope.common.lib.types.PropagationByResource; import org.apache.syncope.core.misc.ConnObjectUtils; @@ -80,6 +78,7 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; import org.apache.syncope.core.persistence.api.entity.Membership; import org.apache.syncope.core.persistence.api.entity.Realm; import org.apache.syncope.core.persistence.api.entity.Relationship; +import org.apache.syncope.core.persistence.api.entity.VirSchema; import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject; import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; import org.apache.syncope.core.persistence.api.entity.resource.MappingItem; @@ -130,9 +129,6 @@ abstract class AbstractAnyDataBinder { protected DerAttrDAO derAttrDAO; @Autowired - protected VirAttrDAO virAttrDAO; - - @Autowired protected PlainAttrValueDAO plainAttrValueDAO; @Autowired @@ -159,7 +155,7 @@ abstract class AbstractAnyDataBinder { @Autowired protected MappingUtils mappingUtils; - protected void setRealm(final Any<?, ?, ?> any, final AnyPatch anyPatch) { + 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()); if (newRealm == null) { @@ -225,7 +221,7 @@ abstract class AbstractAnyDataBinder { } } - private List<String> evaluateMandatoryCondition(final Provision provision, final Any<?, ?, ?> any) { + private List<String> evaluateMandatoryCondition(final Provision provision, final Any<?, ?> any) { List<String> missingAttrNames = new ArrayList<>(); if (provision != null) { @@ -235,7 +231,7 @@ abstract class AbstractAnyDataBinder { || item.getPurpose() == MappingPurpose.BOTH)) { List<PlainAttrValue> values = mappingUtils.getIntValues( - provision, item, Collections.<Any<?, ?, ?>>singletonList(any), null); + provision, item, Collections.<Any<?, ?>>singletonList(any)); if (values.isEmpty() && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) { missingAttrNames.add(item.getIntAttrName()); } @@ -247,7 +243,7 @@ abstract class AbstractAnyDataBinder { } private SyncopeClientException checkMandatoryOnResources( - final Any<?, ?, ?> any, final Set<ExternalResource> resources) { + final Any<?, ?> any, final Set<ExternalResource> resources) { SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing); @@ -266,7 +262,7 @@ abstract class AbstractAnyDataBinder { return reqValMissing; } - private SyncopeClientException checkMandatory(final Any<?, ?, ?> any) { + private SyncopeClientException checkMandatory(final Any<?, ?> any) { SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing); // Check if there is some mandatory schema defined for which no value has been provided @@ -284,7 +280,7 @@ abstract class AbstractAnyDataBinder { return reqValMissing; } - private Set<ExternalResource> getAllResources(final Any<?, ?, ?> any) { + private Set<ExternalResource> getAllResources(final Any<?, ?> any) { Set<ExternalResource> resources = new HashSet<>(); if (any instanceof User) { @@ -323,21 +319,26 @@ abstract class AbstractAnyDataBinder { switch (patch.getOperation()) { case ADD_REPLACE: - virAttrHander.updateOnResourcesIfMappingMatches( - any, schema.getKey(), resources, anyUtils.plainIntMappingType(), propByRes); - // 1.1 remove values - Collection<Long> valuesToBeRemoved = attr.getSchema().isUniqueConstraint() - ? Collections.singleton(attr.getUniqueValue().getKey()) - : CollectionUtils.collect(attr.getValues(), new Transformer<PlainAttrValue, Long>() { - - @Override - public Long transform(final PlainAttrValue input) { - return input.getKey(); - } - }); - for (Long attrValueKey : valuesToBeRemoved) { - plainAttrValueDAO.delete(attrValueKey, anyUtils.plainAttrValueClass()); + if (attr.getSchema().isUniqueConstraint()) { + if (attr.getUniqueValue() != null + && !patch.getAttrTO().getValues().isEmpty() + && !patch.getAttrTO().getValues().get(0).equals(attr.getUniqueValue().getValueAsString())) { + + plainAttrValueDAO.delete(attr.getUniqueValue().getKey(), anyUtils.plainAttrUniqueValueClass()); + } + } else { + Collection<Long> valuesToBeRemoved = CollectionUtils.collect(attr.getValues(), + new Transformer<PlainAttrValue, Long>() { + + @Override + public Long transform(final PlainAttrValue input) { + return input.getKey(); + } + }); + for (Long attrValueKey : valuesToBeRemoved) { + plainAttrValueDAO.delete(attrValueKey, anyUtils.plainAttrValueClass()); + } } // 1.2 add values @@ -359,22 +360,20 @@ abstract class AbstractAnyDataBinder { default: any.remove(attr); plainAttrDAO.delete(attr.getKey(), anyUtils.plainAttrClass()); + } - for (ExternalResource resource : resources) { - for (MappingItem mapItem - : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) { - - if (schema.getKey().equals(mapItem.getIntAttrName()) - && mapItem.getIntMappingType() == anyUtils.plainIntMappingType()) { + for (ExternalResource resource : resources) { + for (MappingItem mapItem : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) { + if (schema.getKey().equals(mapItem.getIntAttrName()) + && mapItem.getIntMappingType() == anyUtils.plainIntMappingType()) { - propByRes.add(ResourceOperation.UPDATE, resource.getKey()); + propByRes.add(ResourceOperation.UPDATE, resource.getKey()); - if (mapItem.isConnObjectKey() && !attr.getValuesAsStrings().isEmpty()) { - propByRes.addOldConnObjectKey(resource.getKey(), attr.getValuesAsStrings().get(0)); - } - } + if (mapItem.isConnObjectKey() && !attr.getValuesAsStrings().isEmpty()) { + propByRes.addOldConnObjectKey(resource.getKey(), attr.getValuesAsStrings().get(0)); } } + } } } @@ -400,36 +399,26 @@ abstract class AbstractAnyDataBinder { } } - switch (patch.getOperation()) { - case ADD_REPLACE: - virAttrHander.updateOnResourcesIfMappingMatches( - any, schema.getKey(), resources, anyUtils.derIntMappingType(), propByRes); - break; - - case DELETE: - default: - derAttrDAO.delete(attr); - - for (ExternalResource resource : resources) { - for (MappingItem mapItem - : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) { + if (patch.getOperation() == PatchOperation.DELETE) { + derAttrDAO.delete(attr); + } - if (schema.getKey().equals(mapItem.getIntAttrName()) - && mapItem.getIntMappingType() == anyUtils.derIntMappingType()) { + for (ExternalResource resource : resources) { + for (MappingItem mapItem : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) { + if (schema.getKey().equals(mapItem.getIntAttrName()) + && mapItem.getIntMappingType() == anyUtils.derIntMappingType()) { - propByRes.add(ResourceOperation.UPDATE, resource.getKey()); + propByRes.add(ResourceOperation.UPDATE, resource.getKey()); - if (mapItem.isConnObjectKey() && !attr.getValue(any.getPlainAttrs()).isEmpty()) { - propByRes.addOldConnObjectKey(resource.getKey(), attr.getValue(any.getPlainAttrs())); - } - } + if (mapItem.isConnObjectKey() && !attr.getValue(any.getPlainAttrs()).isEmpty()) { + propByRes.addOldConnObjectKey(resource.getKey(), attr.getValue(any.getPlainAttrs())); } } + } } } - @SuppressWarnings("rawtypes") - protected PropagationByResource fill(final Any any, final AnyPatch anyPatch, final AnyUtils anyUtils, + protected PropagationByResource fill(final Any<?, ?> any, final AnyPatch anyPatch, final AnyUtils anyUtils, final SyncopeClientCompositeException scce) { PropagationByResource propByRes = new PropagationByResource(); @@ -576,25 +565,12 @@ abstract class AbstractAnyDataBinder { } } - // 3. virtual attributes - for (AttrTO vattrTO : anyTO.getVirAttrs()) { - VirSchema virSchema = virAttrHander.getVirSchema(vattrTO.getSchema()); - if (virSchema != null) { - VirAttr virAttr = anyUtils.newVirAttr(); - virAttr.setOwner(any); - virAttr.setSchema(virSchema); - any.add(virAttr); - } - } - SyncopeClientException requiredValuesMissing = checkMandatory(any); if (!requiredValuesMissing.isEmpty()) { scce.addException(requiredValuesMissing); } - virAttrHander.createVirtual(any, anyTO.getVirAttrs()); - - // 4. realm & resources + // 3. realm & resources Realm realm = realmDAO.find(anyTO.getRealm()); if (realm == null) { SyncopeClientException noRealm = SyncopeClientException.build(ClientExceptionType.InvalidRealm); @@ -628,7 +604,7 @@ abstract class AbstractAnyDataBinder { final Collection<? extends AnyTypeClass> auxClasses, final Collection<? extends PlainAttr<?>> attrs, final Collection<? extends DerAttr<?>> derAttrs, - final Collection<? extends VirAttr<?>> virAttrs, + final Map<VirSchema, List<String>> virAttrs, final Collection<? extends ExternalResource> resources) { anyTO.setRealm(realmFullPath); @@ -659,11 +635,11 @@ abstract class AbstractAnyDataBinder { anyTO.getDerAttrs().add(attrTO); } - for (VirAttr<?> virAttr : virAttrs) { + for (Map.Entry<VirSchema, List<String>> entry : virAttrs.entrySet()) { AttrTO attrTO = new AttrTO(); - attrTO.setSchema(virAttr.getSchema().getKey()); - attrTO.getValues().addAll(virAttr.getValues()); - attrTO.setReadonly(virAttr.getSchema().isReadonly()); + attrTO.setSchema(entry.getKey().getKey()); + attrTO.getValues().addAll(entry.getValue()); + attrTO.setReadonly(entry.getKey().isReadonly()); anyTO.getVirAttrs().add(attrTO); } @@ -673,21 +649,21 @@ abstract class AbstractAnyDataBinder { } } - protected RelationshipTO getRelationshipTO(final Relationship<? extends Any<?, ?, ?>, AnyObject> relationship) { + protected RelationshipTO getRelationshipTO(final Relationship<? extends Any<?, ?>, AnyObject> relationship) { return new RelationshipTO.Builder(). left(relationship.getLeftEnd().getType().getKey(), relationship.getLeftEnd().getKey()). right(relationship.getRightEnd().getType().getKey(), relationship.getRightEnd().getKey()). build(); } - protected MembershipTO getMembershipTO(final Membership<? extends Any<?, ?, ?>> membership) { + protected MembershipTO getMembershipTO(final Membership<? extends Any<?, ?>> membership) { return new MembershipTO.Builder(). left(membership.getLeftEnd().getType().getKey(), membership.getLeftEnd().getKey()). group(membership.getRightEnd().getKey(), membership.getRightEnd().getName()). build(); } - protected Map<String, String> getConnObjectKeys(final Any<?, ?, ?> any) { + protected Map<String, String> getConnObjectKeys(final Any<?, ?> any) { Map<String, String> connObjectKeys = new HashMap<>(); Iterable<? extends ExternalResource> iterable = any instanceof User http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java index 91edd7e..2dca6e4 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java @@ -19,7 +19,9 @@ package org.apache.syncope.core.provisioning.java.data; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections4.CollectionUtils; @@ -41,6 +43,7 @@ import org.apache.syncope.core.misc.spring.BeanUtils; import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO; import org.apache.syncope.core.persistence.api.entity.AnyType; import org.apache.syncope.core.persistence.api.entity.RelationshipType; +import org.apache.syncope.core.persistence.api.entity.VirSchema; import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership; import org.apache.syncope.core.persistence.api.entity.anyobject.ARelationship; import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject; @@ -75,12 +78,12 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An BeanUtils.copyProperties(anyObject, anyObjectTO, IGNORE_PROPERTIES); - if (details) { - virAttrHander.retrieveVirAttrValues(anyObject); - } + Map<VirSchema, List<String>> virAttrValues = details + ? virAttrHander.getValues(anyObject) + : Collections.<VirSchema, List<String>>emptyMap(); fillTO(anyObjectTO, anyObject.getRealm().getFullPath(), anyObject.getAuxClasses(), - anyObject.getPlainAttrs(), anyObject.getDerAttrs(), anyObject.getVirAttrs(), + anyObject.getPlainAttrs(), anyObject.getDerAttrs(), virAttrValues, anyObjectDAO.findAllResources(anyObject)); if (details) { http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java index 155034c..620cdf8 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java @@ -18,6 +18,8 @@ */ package org.apache.syncope.core.provisioning.java.data; +import java.util.Collections; +import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.common.lib.SyncopeClientCompositeException; @@ -34,6 +36,7 @@ import org.apache.syncope.core.provisioning.api.data.GroupDataBinder; import org.apache.syncope.core.misc.search.SearchCondConverter; import org.apache.syncope.core.persistence.api.dao.search.SearchCond; import org.apache.syncope.core.persistence.api.entity.DynGroupMembership; +import org.apache.syncope.core.persistence.api.entity.VirSchema; import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership; import org.apache.syncope.core.persistence.api.entity.user.UDynGroupMembership; import org.springframework.stereotype.Component; @@ -203,12 +206,12 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD groupTO.setGroupOwner(group.getGroupOwner().getKey()); } - if (details) { - virAttrHander.retrieveVirAttrValues(group); - } + Map<VirSchema, List<String>> virAttrValues = details + ? virAttrHander.getValues(group) + : Collections.<VirSchema, List<String>>emptyMap(); fillTO(groupTO, group.getRealm().getFullPath(), group.getAuxClasses(), - group.getPlainAttrs(), group.getDerAttrs(), group.getVirAttrs(), group.getResources()); + group.getPlainAttrs(), group.getDerAttrs(), virAttrValues, group.getResources()); if (group.getADynMembership() != null) { groupTO.setADynMembershipCond(group.getADynMembership().getFIQLCond()); http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java index e5dfadf..d04dfd3 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java @@ -21,9 +21,8 @@ package org.apache.syncope.core.provisioning.java.data; import org.apache.syncope.core.provisioning.api.data.ResourceDataBinder; import java.util.Collection; import java.util.HashSet; +import java.util.Iterator; import java.util.Set; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.collections4.Predicate; import org.apache.commons.lang3.SerializationUtils; import org.apache.syncope.common.lib.SyncopeClientCompositeException; import org.apache.syncope.common.lib.SyncopeClientException; @@ -50,7 +49,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.syncope.core.misc.spring.BeanUtils; import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO; +import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO; import org.apache.syncope.core.persistence.api.entity.AnyType; +import org.apache.syncope.core.persistence.api.entity.VirSchema; import org.apache.syncope.core.persistence.api.entity.resource.Provision; import org.identityconnectors.framework.common.objects.ObjectClass; import org.springframework.beans.factory.annotation.Autowired; @@ -76,6 +77,9 @@ public class ResourceDataBinderImpl implements ResourceDataBinder { private PolicyDAO policyDAO; @Autowired + private VirSchemaDAO virSchemaDAO; + + @Autowired private EntityFactory entityFactory; @Override @@ -112,7 +116,8 @@ public class ResourceDataBinderImpl implements ResourceDataBinder { for (ProvisionTO provisionTO : resourceTO.getProvisions()) { AnyType anyType = anyTypeDAO.find(provisionTO.getAnyType()); if (anyType == null) { - LOG.debug("Invalid AnyType specified {}, ignoring...", provisionTO.getAnyType()); + LOG.debug("Invalid {} specified {}, ignoring...", + AnyType.class.getSimpleName(), provisionTO.getAnyType()); } else { Provision provision = resource.getProvision(anyType); if (provision == null) { @@ -124,7 +129,7 @@ public class ResourceDataBinderImpl implements ResourceDataBinder { if (provisionTO.getObjectClass() == null) { SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidProvision); - sce.getElements().add("Null ObjectClass"); + sce.getElements().add("Null " + ObjectClass.class.getSimpleName()); throw sce; } provision.setObjectClass(new ObjectClass(provisionTO.getObjectClass())); @@ -146,17 +151,36 @@ public class ResourceDataBinderImpl implements ResourceDataBinder { } populateMapping(provisionTO.getMapping(), mapping, entityFactory.newEntity(MappingItem.class)); } + + if (provisionTO.getVirSchemas().isEmpty()) { + for (VirSchema schema : virSchemaDAO.findByProvision(provision)) { + virSchemaDAO.delete(schema.getKey()); + } + } else { + for (String schemaName : provisionTO.getVirSchemas()) { + VirSchema schema = virSchemaDAO.find(schemaName); + if (schema == null) { + LOG.debug("Invalid {} specified: {}, ignoring...", + VirSchema.class.getSimpleName(), schemaName); + } else { + schema.setProvision(provision); + } + } + } } } - // 2. remove all abouts not contained in the TO - CollectionUtils.filter(resource.getProvisions(), new Predicate<Provision>() { + // 2. remove all provisions not contained in the TO + for (Iterator<? extends Provision> itor = resource.getProvisions().iterator(); itor.hasNext();) { + Provision provision = itor.next(); + if (resourceTO.getProvision(provision.getAnyType().getKey()) == null) { + for (VirSchema schema : virSchemaDAO.findByProvision(provision)) { + virSchemaDAO.delete(schema.getKey()); + } - @Override - public boolean evaluate(final Provision provision) { - return resourceTO.getProvision(provision.getAnyType().getKey()) != null; + itor.remove(); } - }); + } resource.setCreateTraceLevel(resourceTO.getCreateTraceLevel()); resource.setUpdateTraceLevel(resourceTO.getUpdateTraceLevel()); @@ -310,6 +334,10 @@ public class ResourceDataBinderImpl implements ResourceDataBinder { populateMappingTO(provision.getMapping(), mappingTO); } + for (VirSchema virSchema : virSchemaDAO.findByProvision(provision)) { + provisionTO.getVirSchemas().add(virSchema.getKey()); + } + resourceTO.getProvisions().add(provisionTO); } http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java index 0794f8c..006a998 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java @@ -35,11 +35,13 @@ import org.apache.syncope.core.misc.spring.BeanUtils; import org.apache.syncope.core.misc.jexl.JexlUtils; import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO; import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO; +import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO; import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO; import org.apache.syncope.core.persistence.api.entity.AnyTypeClass; import org.apache.syncope.core.persistence.api.entity.AnyUtils; import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; import org.apache.syncope.core.persistence.api.entity.EntityFactory; +import org.apache.syncope.core.persistence.api.entity.resource.Provision; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -50,7 +52,7 @@ public class SchemaDataBinderImpl implements SchemaDataBinder { private static final Logger LOG = LoggerFactory.getLogger(SchemaDataBinder.class); - private static final String[] IGNORE_PROPERTIES = { "anyTypeClass" }; + private static final String[] IGNORE_PROPERTIES = { "anyTypeClass", "provision" }; @Autowired private AnyTypeClassDAO anyTypeClassDAO; @@ -65,6 +67,9 @@ public class SchemaDataBinderImpl implements SchemaDataBinder { private VirSchemaDAO virSchemaDAO; @Autowired + private ExternalResourceDAO resourceDAO; + + @Autowired private EntityFactory entityFactory; @Autowired @@ -235,6 +240,14 @@ public class SchemaDataBinderImpl implements SchemaDataBinder { merged.setAnyTypeClass(null); } + Provision provision = resourceDAO.findProvision(schemaTO.getProvision()); + if (provision == null) { + SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSchemaDefinition); + sce.getElements().add("Provision " + schemaTO.getProvision() + " not found"); + throw sce; + } + merged.setProvision(provision); + return merged; } @@ -253,6 +266,7 @@ public class SchemaDataBinderImpl implements SchemaDataBinder { VirSchemaTO schemaTO = new VirSchemaTO(); BeanUtils.copyProperties(schema, schemaTO, IGNORE_PROPERTIES); schemaTO.setAnyTypeClass(schema.getAnyTypeClass() == null ? null : schema.getAnyTypeClass().getKey()); + schemaTO.setProvision(schema.getProvision().getKey()); return schemaTO; } http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java index 3420d27..4bb7bdf 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java @@ -19,8 +19,10 @@ package org.apache.syncope.core.provisioning.java.data; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Resource; @@ -57,6 +59,7 @@ import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO; import org.apache.syncope.core.persistence.api.dao.RoleDAO; import org.apache.syncope.core.persistence.api.entity.RelationshipType; import org.apache.syncope.core.persistence.api.entity.Role; +import org.apache.syncope.core.persistence.api.entity.VirSchema; import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject; import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; import org.apache.syncope.core.persistence.api.entity.resource.MappingItem; @@ -431,12 +434,12 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat userTO.setSecurityQuestion(user.getSecurityQuestion().getKey()); } - if (details) { - virAttrHander.retrieveVirAttrValues(user); - } + Map<VirSchema, List<String>> virAttrValues = details + ? virAttrHander.getValues(user) + : Collections.<VirSchema, List<String>>emptyMap(); fillTO(userTO, user.getRealm().getFullPath(), user.getAuxClasses(), - user.getPlainAttrs(), user.getDerAttrs(), user.getVirAttrs(), userDAO.findAllResources(user)); + user.getPlainAttrs(), user.getDerAttrs(), virAttrValues, userDAO.findAllResources(user)); if (details) { // roles http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java index dbfeca5..7c6d34c 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java @@ -21,7 +21,7 @@ package org.apache.syncope.core.provisioning.java.job; import java.util.Date; import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.lang3.ClassUtils; -import org.apache.syncope.core.misc.DataFormat; +import org.apache.syncope.core.misc.FormatUtils; import org.apache.syncope.core.misc.security.AuthContextUtils; import org.apache.syncope.core.misc.spring.ApplicationContextProvider; import org.apache.syncope.core.provisioning.api.job.JobInstanceLoader; @@ -114,7 +114,7 @@ public class TaskJob implements InterruptableJob { if (thread == null) { LOG.warn("Unable to retrieve the thread of the current job execution"); } else { - LOG.info("Interrupting job from thread {} at {} ", thread.getId(), DataFormat.format(new Date())); + LOG.info("Interrupting job from thread {} at {} ", thread.getId(), FormatUtils.format(new Date())); if (interruptMaxRetries < 1) { interruptMaxRetries = 1; http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java index 412b978..fd4af1b 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java @@ -50,16 +50,17 @@ import org.apache.syncope.core.persistence.api.entity.task.NotificationTask; import org.apache.syncope.core.persistence.api.entity.task.TaskExec; import org.apache.syncope.core.persistence.api.entity.user.UDerAttr; import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr; -import org.apache.syncope.core.persistence.api.entity.user.UVirAttr; import org.apache.syncope.core.persistence.api.entity.user.User; import org.apache.syncope.core.provisioning.api.data.GroupDataBinder; import org.apache.syncope.core.provisioning.api.data.UserDataBinder; import org.apache.syncope.core.misc.search.SearchCondConverter; import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO; import org.apache.syncope.core.persistence.api.dao.AnySearchDAO; +import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO; import org.apache.syncope.core.persistence.api.entity.Any; import org.apache.syncope.core.persistence.api.entity.AnyAbout; import org.apache.syncope.core.persistence.api.entity.AnyType; +import org.apache.syncope.core.persistence.api.entity.VirSchema; import org.apache.syncope.core.provisioning.api.VirAttrHandler; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; @@ -76,9 +77,6 @@ import org.springframework.transaction.annotation.Transactional; @Transactional(rollbackFor = { Throwable.class }) public class NotificationManagerImpl implements NotificationManager { - /** - * Logger. - */ private static final Logger LOG = LoggerFactory.getLogger(NotificationManager.class); public static final String MAIL_TEMPLATES = "mailTemplates/"; @@ -87,6 +85,9 @@ public class NotificationManagerImpl implements NotificationManager { public static final String MAIL_TEMPLATE_TEXT_SUFFIX = ".txt.vm"; + @Autowired + private VirSchemaDAO virSchemaDAO; + /** * Notification DAO. */ @@ -169,11 +170,11 @@ public class NotificationManagerImpl implements NotificationManager { */ private NotificationTask getNotificationTask( final Notification notification, - final Any<?, ?, ?> any, + final Any<?, ?> any, final Map<String, Object> model) { if (any != null) { - virAttrHander.retrieveVirAttrValues(any); + virAttrHander.getValues(any); } List<User> recipients = new ArrayList<>(); @@ -191,7 +192,7 @@ public class NotificationManagerImpl implements NotificationManager { Set<String> recipientEmails = new HashSet<>(); List<UserTO> recipientTOs = new ArrayList<>(recipients.size()); for (User recipient : recipients) { - virAttrHander.retrieveVirAttrValues(recipient); + virAttrHander.getValues(recipient); String email = getRecipientEmail(notification.getRecipientAttrType(), notification.getRecipientAttrName(), recipient); @@ -267,7 +268,7 @@ public class NotificationManagerImpl implements NotificationManager { final Object output, final Object... input) { - Any<?, ?, ?> any = null; + Any<?, ?> any = null; if (before instanceof UserTO) { any = userDAO.find(((UserTO) before).getKey()); @@ -357,9 +358,12 @@ public class NotificationManagerImpl implements NotificationManager { break; case UserVirtualSchema: - UVirAttr virAttr = user.getVirAttr(recipientAttrName); - if (virAttr != null) { - email = virAttr.getValues().isEmpty() ? null : virAttr.getValues().get(0); + VirSchema schema = virSchemaDAO.find(recipientAttrName); + if (schema == null) { + LOG.warn("Ignoring non existing {} {}", VirSchema.class.getSimpleName(), recipientAttrName); + } else { + List<String> virAttrValues = virAttrHander.getValues(user, schema); + email = virAttrValues.isEmpty() ? null : virAttrValues.get(0); } break; http://git-wip-us.apache.org/repos/asf/syncope/blob/9cd92305/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 69a2e9d..316f91a 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 @@ -27,6 +27,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.commons.collections4.IteratorUtils; import org.apache.syncope.common.lib.types.AuditElements; import org.apache.syncope.common.lib.types.AuditElements.Result; import org.apache.syncope.common.lib.types.PropagationTaskExecStatus; @@ -49,12 +50,17 @@ import org.apache.syncope.core.misc.ConnObjectUtils; import org.apache.syncope.core.misc.ExceptionUtils2; import org.apache.syncope.core.misc.MappingUtils; import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO; +import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO; import org.apache.syncope.core.persistence.api.entity.Any; +import org.apache.syncope.core.persistence.api.entity.VirSchema; import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject; import org.apache.syncope.core.persistence.api.entity.group.Group; import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; +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.persistence.api.entity.user.User; +import org.apache.syncope.core.provisioning.api.cache.VirAttrCache; +import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue; import org.apache.syncope.core.provisioning.api.notification.NotificationManager; import org.identityconnectors.framework.common.exceptions.ConnectorException; import org.identityconnectors.framework.common.objects.Attribute; @@ -110,6 +116,9 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask @Autowired protected TaskDAO taskDAO; + @Autowired + protected VirSchemaDAO virSchemaDAO; + /** * Notification Manager. */ @@ -125,6 +134,9 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask @Autowired protected EntityFactory entityFactory; + @Autowired + protected VirAttrCache virAttrCache; + @Override public TaskExec execute(final PropagationTask task) { return execute(task, null); @@ -149,12 +161,15 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask } /** - * 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> + * Transform a {@link Collection} of {@link Attribute} instances into a {@link Map}. + * The key to each element in the map is the {@code name} of an {@link Attribute}. + * The value of each element in the map is the {@link Attribute} 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. @@ -173,7 +188,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask final PropagationTask task, final ConnectorObject beforeObj, final Connector connector, - final Set<String> propagationAttempted) { + final Boolean[] propagationAttempted) { // set of attributes to be propagated Set<Attribute> attributes = new HashSet<>(task.getAttributes()); @@ -201,14 +216,10 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask if (beforeObj == null) { LOG.debug("Create {} on {}", attributes, task.getResource().getKey()); - connector.create( - new ObjectClass(task.getObjectClassName()), - attributes, - null, - propagationAttempted); + connector.create(new ObjectClass(task.getObjectClassName()), attributes, null, propagationAttempted); } else { // 1. check if rename is really required - final Name newName = (Name) AttributeUtil.find(Name.NAME, attributes); + Name newName = (Name) AttributeUtil.find(Name.NAME, attributes); LOG.debug("Rename required with value {}", newName); @@ -254,8 +265,8 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask } } - protected Any<?, ?, ?> getAny(final PropagationTask task) { - Any<?, ?, ?> any = null; + protected Any<?, ?> getAny(final PropagationTask task) { + Any<?, ?> any = null; if (task.getAnyKey() != null) { switch (task.getAnyTypeKind()) { @@ -289,8 +300,11 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask return any; } - protected void delete(final PropagationTask task, final ConnectorObject beforeObj, - final Connector connector, final Set<String> propagationAttempted) { + protected void delete( + final PropagationTask task, + final ConnectorObject beforeObj, + final Connector connector, + final Boolean[] propagationAttempted) { if (beforeObj == null) { LOG.debug("{} not found on external resource: ignoring delete", task.getConnObjectKey()); @@ -310,7 +324,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask * update, this user / group used to have the current resource assigned by more than one mean (for example, * two different memberships with the same resource). */ - Any<?, ?, ?> any = getAny(task); + Any<?, ?> any = getAny(task); Collection<String> resources = any instanceof User ? userDAO.findAllResourceNames((User) any) : any instanceof AnyObject @@ -321,11 +335,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask if (!resources.contains(task.getResource().getKey())) { LOG.debug("Delete {} on {}", beforeObj.getUid(), task.getResource().getKey()); - connector.delete( - beforeObj.getObjectClass(), - beforeObj.getUid(), - null, - propagationAttempted); + connector.delete(beforeObj.getObjectClass(), beforeObj.getUid(), null, propagationAttempted); } else { createOrUpdate(task, beforeObj, connector, propagationAttempted); } @@ -345,7 +355,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask String failureReason = null; // Flag to state whether any propagation has been attempted - Set<String> propagationAttempted = new HashSet<>(); + Boolean[] propagationAttempted = new Boolean[] { false }; ConnectorObject beforeObj = null; ConnectorObject afterObj = null; @@ -411,7 +421,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask LOG.error("While executing KO action on {}", execution, wft); } - propagationAttempted.add(task.getOperation().name().toLowerCase()); + propagationAttempted[0] = true; for (PropagationActions action : actions) { action.onError(task, execution, e); @@ -434,7 +444,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask execution.setEndDate(new Date()); if (hasToBeregistered(task, execution)) { - if (propagationAttempted.isEmpty()) { + if (!propagationAttempted[0]) { LOG.debug("No propagation attempted for {}", execution); } else { execution.setTask(task); @@ -535,20 +545,41 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask * @param latest 'FALSE' to retrieve object using old connObjectKey if not null. * @return remote connector object. */ - protected ConnectorObject getRemoteObject(final PropagationTask task, final Connector connector, - final Provision provision, final boolean latest) { + protected ConnectorObject getRemoteObject( + final PropagationTask task, + final Connector connector, + final Provision provision, + final boolean latest) { String connObjectKey = latest || task.getOldConnObjectKey() == null ? task.getConnObjectKey() : task.getOldConnObjectKey(); + List<MappingItem> linkingMappingItems = new ArrayList<>(); + for (VirSchema schema : virSchemaDAO.findByProvision(provision)) { + linkingMappingItems.add(schema.asLinkingMappingItem()); + } + ConnectorObject obj = null; try { obj = connector.getObject( task.getOperation(), new ObjectClass(task.getObjectClassName()), new Uid(connObjectKey), - connector.getOperationOptions(MappingUtils.getPropagationMappingItems(provision))); + connector.getOperationOptions(IteratorUtils.chainedIterator( + MappingUtils.getPropagationMappingItems(provision).iterator(), + linkingMappingItems.iterator()))); + + for (MappingItem item : linkingMappingItems) { + Attribute attr = obj.getAttributeByName(item.getExtAttrName()); + if (attr == null) { + virAttrCache.expire(task.getAnyType(), task.getAnyKey(), item.getIntAttrName()); + } else { + VirAttrCacheValue cacheValue = new VirAttrCacheValue(); + cacheValue.setValues(attr.getValue()); + virAttrCache.put(task.getAnyType(), task.getAnyKey(), item.getIntAttrName(), cacheValue); + } + } } catch (TimeoutException toe) { LOG.debug("Request timeout", toe); throw toe;
