final IntMappingType type,
final Map<String, ConnectorObject> externalResources,
final ConnectorFactory connFactory) {
final String schemaName = virAttr.getSchema().getName();
final VirAttrCacheValue virAttrCacheValue = virAttrCache.get(attrUtil.getType(), owner.getId(), schemaName);
LOG.debug("Retrieve values for virtual attribute {} ({})", schemaName, type);
if (virAttrCache.isValidEntry(virAttrCacheValue)) {
// cached ...
LOG.debug("Values found in cache {}", virAttrCacheValue);
virAttr.setValues(new ArrayList<String>(virAttrCacheValue.getValues()));
} else {
// not cached ...
LOG.debug("Need one or more remote connections");
final VirAttrCacheValue toBeCached = new VirAttrCacheValue();
// SYNCOPE-458 if virattr owner is a Membership, owner must become user involved in membership because
// membership mapping is contained in user mapping
final AbstractSubject realOwner = owner instanceof Membership
? ((Membership) owner).getSyncopeUser()
: (AbstractSubject) owner;
final Set<ExternalResource> targetResources = owner instanceof Membership ? getTargetResource(virAttr, type,
attrUtil, realOwner.getResources()) : getTargetResource(virAttr, type, attrUtil);
for (ExternalResource resource : targetResources) {
LOG.debug("Search values into {}", resource.getName());
try {
final List<AbstractMappingItem> mappings = attrUtil.getMappingItems(resource, MappingPurpose.BOTH);
final ConnectorObject connectorObject;
if (externalResources.containsKey(resource.getName())) {
connectorObject = externalResources.get(resource.getName());
} else {
LOG.debug("Perform connection to {}", resource.getName());
final String accountId = attrUtil.getAccountIdItem(resource) == null
? null
: MappingUtil.getAccountIdValue(
realOwner, resource, attrUtil.getAccountIdItem(resource));
if (StringUtils.isBlank(accountId)) {
throw new IllegalArgumentException("No AccountId found for " + resource.getName());
}
final Connector connector = connFactory.getConnector(resource);
final OperationOptions oo =
connector.getOperationOptions(MappingUtil.getMatchingMappingItems(mappings, type));
connectorObject = connector.getObject(fromAttributable(realOwner), new Uid(accountId), oo);
externalResources.put(resource.getName(), connectorObject);
}
if (connectorObject != null) {
// ask for searched virtual attribute value
final List<AbstractMappingItem> virAttrMappings =
MappingUtil.getMatchingMappingItems(mappings, schemaName, type);
// the same virtual attribute could be mapped with one or more external attribute
for (AbstractMappingItem mapping : virAttrMappings) {
final Attribute attribute = connectorObject.getAttributeByName(mapping.getExtAttrName());
if (attribute != null && attribute.getValue() != null) {
for (Object obj : attribute.getValue()) {
if (obj != null) {
virAttr.getValues().add(obj.toString());
}
}
}
}
toBeCached.setResourceValues(resource.getName(), new HashSet<String>(virAttr.getValues()));
LOG.debug("Retrieved values {}", virAttr.getValues());
}
} catch (Exception e) {
LOG.error("Error reading connector object from {}", resource.getName(), e);
if (virAttrCacheValue != null) {
toBeCached.forceExpiring();
LOG.debug("Search for a cached value (even expired!) ...");
final Set<String> cachedValues = virAttrCacheValue.getValues(resource.getName());
if (cachedValues != null) {
LOG.debug("Use cached value {}", cachedValues);
virAttr.getValues().addAll(cachedValues);
toBeCached.setResourceValues(resource.getName(), new HashSet<String>(cachedValues));
}
}
}
}