Commit d7531393 authored by Radovan Semancik's avatar Radovan Semancik
Browse files

PolyString support, almost untested (MID-5210)

parent c422438a
......@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.ArrayUtils;
......@@ -846,19 +847,30 @@ public abstract class AbstractLdapConnector<C extends AbstractLdapConfiguration>
}
entry.put("objectClass", ldapObjectClassNames);
for (Attribute icfAttr: createAttributes) {
if (icfAttr.is(Name.NAME)) {
for (Attribute connIdAttr: createAttributes) {
if (connIdAttr.is(Name.NAME)) {
continue;
}
if (icfAttr.is(PredefinedAttributes.AUXILIARY_OBJECT_CLASS_NAME)) {
if (connIdAttr.is(PredefinedAttributes.AUXILIARY_OBJECT_CLASS_NAME)) {
continue;
}
AttributeType ldapAttrType = shcemaTranslator.toLdapAttribute(ldapStructuralObjectClass, icfAttr.getName());
List<Value> ldapValues = shcemaTranslator.toLdapValues(ldapAttrType, icfAttr.getValue());
// Do NOT set attributeType here. The attributeType may not match the type of the value.
entry.put(ldapAttrType.getName(), ldapValues.toArray(new Value[ldapValues.size()]));
// no simple way how to check if he attribute was added. It may end up with ERR_04451. So let's just
// hope that it worked well. It should - unless there is a connector bug.
AttributeType ldapAttributeType = shcemaTranslator.toLdapAttribute(ldapStructuralObjectClass, connIdAttr.getName());
List<Object> connIdAttrValues = connIdAttr.getValue();
if (schemaTranslator.isPolyAttribute(ldapAttributeType, connIdAttrValues)) {
Map<String,List<Value>> valueMap = schemaTranslator.toLdapPolyValues(ldapAttributeType, connIdAttrValues);
for (Map.Entry<String, List<Value>> valueMapEntry : valueMap.entrySet()) {
LOG.ok("Adding poly attribute {0}: {1}", valueMapEntry.getKey(), valueMapEntry.getValue());
// Do NOT set attributeType here. The attributeType may not match the type of the value.
entry.put(valueMapEntry.getKey(), valueMapEntry.getValue().toArray(new Value[valueMapEntry.getValue().size()]));
}
} else {
List<Value> ldapValues = shcemaTranslator.toLdapValues(ldapAttributeType, connIdAttrValues);
// Do NOT set attributeType here. The attributeType may not match the type of the value.
entry.put(ldapAttributeType.getName(), ldapValues.toArray(new Value[ldapValues.size()]));
// no simple way how to check if he attribute was added. It may end up with ERR_04451. So let's just
// hope that it worked well. It should - unless there is a connector bug.
}
}
preCreate(ldapStructuralObjectClass, entry);
......@@ -1107,22 +1119,33 @@ public abstract class AbstractLdapConnector<C extends AbstractLdapConfiguration>
}
private void addLdapModification(List<Modification> ldapModifications,
ModificationOperation modOp, AttributeType ldapAttributeType, List<Object> values) {
if (values == null) {
ModificationOperation modOp, AttributeType ldapAttributeType, List<Object> connIdValues) {
if (connIdValues == null) {
return;
}
List<Value> ldapValues = schemaTranslator.toLdapValues(ldapAttributeType, values);
if (ldapValues == null || ldapValues.isEmpty()) {
// Do NOT set AttributeType here
// The attributeType might not match the Value class
// e.g. human-readable jpegPhoto attribute will expect StringValue
ldapModifications.add(new DefaultModification(modOp, ldapAttributeType.getName()));
if (schemaTranslator.isPolyAttribute(ldapAttributeType, connIdValues)) {
Map<String,List<Value>> valueMap = schemaTranslator.toLdapPolyValues(ldapAttributeType, connIdValues);
for (Map.Entry<String, List<Value>> valueMapEntry : valueMap.entrySet()) {
// Do NOT set AttributeType here
// The attributeType might not match the Value class
// e.g. human-readable jpegPhoto attribute will expect StringValue
DefaultAttribute ldapAttribute = new DefaultAttribute(valueMapEntry.getKey(), valueMapEntry.getValue().toArray(new Value[valueMapEntry.getValue().size()]));
ldapModifications.add(new DefaultModification(modOp, ldapAttribute));
}
} else {
// Do NOT set AttributeType here
// The attributeType might not match the Value class
// e.g. human-readable jpegPhoto attribute will expect StringValue
DefaultAttribute ldapAttribute = new DefaultAttribute(ldapAttributeType.getName(), ldapValues.toArray(new Value[ldapValues.size()]));
ldapModifications.add(new DefaultModification(modOp, ldapAttribute));
List<Value> ldapValues = schemaTranslator.toLdapValues(ldapAttributeType, connIdValues);
if (ldapValues == null || ldapValues.isEmpty()) {
// Do NOT set AttributeType here
// The attributeType might not match the Value class
// e.g. human-readable jpegPhoto attribute will expect StringValue
ldapModifications.add(new DefaultModification(modOp, ldapAttributeType.getName()));
} else {
// Do NOT set AttributeType here
// The attributeType might not match the Value class
// e.g. human-readable jpegPhoto attribute will expect StringValue
DefaultAttribute ldapAttribute = new DefaultAttribute(ldapAttributeType.getName(), ldapValues.toArray(new Value[ldapValues.size()]));
ldapModifications.add(new DefaultModification(modOp, ldapAttribute));
}
}
}
......
/*
* Copyright (c) 2015-2016 Evolveum
* Copyright (c) 2015-2019 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -50,6 +50,11 @@ public class LdapConfiguration extends AbstractLdapConfiguration {
* optional additional search filter in the OpenLDAP access log
*/
private String openLdapAccessLogAdditionalFilter;
/**
* Attribute that supports language tag (RFC 3866).
*/
private String[] languageTagAttributes;
@ConfigurationProperty(order = 100)
public String getLockoutStrategy() {
......@@ -68,7 +73,7 @@ public class LdapConfiguration extends AbstractLdapConfiguration {
super.recompute();
}
@ConfigurationProperty(order = 42)
@ConfigurationProperty(order = 101)
public String getOpenLdapAccessLogDn() {
return this.openLdapAccessLogDn;
}
......@@ -77,7 +82,7 @@ public class LdapConfiguration extends AbstractLdapConfiguration {
this.openLdapAccessLogDn = accessLogDn;
}
@ConfigurationProperty(order = 43)
@ConfigurationProperty(order = 102)
public String getOpenLdapAccessLogAdditionalFilter() {
return this.openLdapAccessLogAdditionalFilter;
}
......@@ -86,4 +91,15 @@ public class LdapConfiguration extends AbstractLdapConfiguration {
this.openLdapAccessLogAdditionalFilter = accessLogAditionalFilter;
}
@ConfigurationProperty(order = 103)
public String[] getLanguageTagAttributes() {
return languageTagAttributes;
}
public void setLanguageTagAttributes(String[] languageTagAttribute) {
this.languageTagAttributes = languageTagAttribute;
}
}
\ No newline at end of file
/**
* Copyright (c) 2016-2017 Evolveum
* Copyright (c) 2016-2019 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -16,26 +16,43 @@
package com.evolveum.polygon.connector.ldap;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.directory.api.ldap.model.constants.SchemaConstants;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.entry.Value;
import org.apache.directory.api.ldap.model.schema.AttributeType;
import org.apache.directory.api.ldap.model.schema.LdapSyntax;
import org.apache.directory.api.ldap.model.schema.SchemaManager;
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.framework.common.exceptions.InvalidAttributeValueException;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
import org.identityconnectors.framework.common.objects.AttributeInfo;
import org.identityconnectors.framework.common.objects.AttributeInfoBuilder;
import org.identityconnectors.framework.common.objects.AttributeValueCompleteness;
import org.identityconnectors.framework.common.objects.ConnectorObjectBuilder;
import org.identityconnectors.framework.common.objects.ObjectClassInfoBuilder;
import org.identityconnectors.framework.common.objects.OperationalAttributes;
import com.evolveum.polygon.connector.ldap.LdapUtil;
import com.evolveum.polygon.connector.ldap.schema.AbstractSchemaTranslator;
import com.evolveum.polygon.connector.ldap.schema.AttributeHandler;
/**
* @author semancik
*
*/
public class LdapSchemaTranslator extends AbstractSchemaTranslator<LdapConfiguration> {
// TODO: move to polygon
public static final String POLYSTRING_SUBTYPE = "http://midpoint.evolveum.com/xml/ns/public/connector/icf-1/subtypes#PolyString";
public static final String POLYSTRING_ORIG_KEY = "";
private static final Log LOG = Log.getLog(LdapSchemaTranslator.class);
......@@ -73,6 +90,78 @@ public class LdapSchemaTranslator extends AbstractSchemaTranslator<LdapConfigura
return computedOperationalAttributes;
}
@Override
public Class<?> toConnIdType(LdapSyntax syntax, String connIdAttributeName) {
if (supportsLanguageTag(connIdAttributeName)) {
return Map.class;
} else {
return super.toConnIdType(syntax, connIdAttributeName);
}
}
@Override
public String toConnIdSubtype(Class<?> connIdType, AttributeType ldapAttribute, String connIdAttributeName) {
if (supportsLanguageTag(connIdAttributeName)) {
return POLYSTRING_SUBTYPE;
} else {
return super.toConnIdSubtype(connIdType, ldapAttribute, connIdAttributeName);
}
}
private boolean supportsLanguageTag(String connIdAttributeName) {
if (getConfiguration().getLanguageTagAttributes() == null) {
return false;
}
for (String languageTagAttribute : getConfiguration().getLanguageTagAttributes()) {
if (connIdAttributeName.equals(languageTagAttribute)) {
return true;
}
}
return false;
}
@Override
public boolean isPolyAttribute(AttributeType ldapAttributeType, List<Object> values) {
if (values == null) {
return false;
}
if (values.size() != 1) {
return false;
}
Object value = values.get(0);
return value instanceof Map;
}
@Override
public boolean isPolyAttribute(AttributeInfo connIdAttributeInfo) {
return Map.class.isAssignableFrom(connIdAttributeInfo.getType());
}
@Override
public Map<String, List<Value>> toLdapPolyValues(AttributeType ldapAttributeType, List<Object> connIdValues) {
Map<String, List<Value>> ldapValueMap = new HashMap<>();
if (connIdValues.size() > 1) {
throw new InvalidAttributeValueException("Only single-valued poly attributes are supported (attribute '"+ldapAttributeType.getName()+"')");
}
Object connId = connIdValues.get(0);
if (!(connId instanceof Map)) {
throw new InvalidAttributeValueException("Only map-valued poly attributes are supported (attribute '"+ldapAttributeType.getName()+"'), got "+connId.getClass()+" instead");
}
Map<String,String> connIdValueMap = (Map<String,String>)connId;
// TODO: check if this is really polystring
for (Map.Entry<String, String> connIdValueMapEntry : connIdValueMap.entrySet()) {
String attrName;
if (connIdValueMapEntry.getKey().equals(POLYSTRING_ORIG_KEY)) {
attrName = ldapAttributeType.getName();
} else {
attrName = ldapAttributeType.getName() + ";lang-" + connIdValueMapEntry.getKey();
}
List<Value> ldapValues = toLdapValues(ldapAttributeType, Collections.singletonList(connIdValueMapEntry.getValue()));
ldapValueMap.put(attrName, ldapValues);
}
return ldapValueMap;
}
@Override
public AttributeType toLdapAttribute(org.apache.directory.api.ldap.model.schema.ObjectClass ldapObjectClass,
String icfAttributeName) {
......@@ -89,6 +178,61 @@ public class LdapSchemaTranslator extends AbstractSchemaTranslator<LdapConfigura
return super.toLdapAttribute(ldapObjectClass, icfAttributeName);
}
@Override
protected Attribute toConnIdAttributePoly(String connIdAttributeName, String ldapAttributeNameFromSchema, AttributeType ldapAttributeType,
List<org.apache.directory.api.ldap.model.entry.Attribute> ldapAttributes,
LdapNetworkConnection connection, Entry entry, AttributeHandler attributeHandler) {
AttributeBuilder ab = new AttributeBuilder();
ab.setName(connIdAttributeName);
Map<String,Object> connIdValueMap = new HashMap<>();
for (org.apache.directory.api.ldap.model.entry.Attribute ldapAttribute : ldapAttributes) {
String option = getLdapAttributeOption(ldapAttribute);
if (option != null && !option.startsWith("lang-")) {
LOG.ok("Skipping unknown option {0} on attribute {1}", option, ldapAttributeNameFromSchema);
continue;
}
if (ldapAttribute.size() == 0) {
LOG.ok("Skipping empty attribute {0};{1}", ldapAttributeNameFromSchema, option);
continue;
}
if (ldapAttribute.size() > 1) {
throw new InvalidAttributeValueException("Multi-valued multi-attributes are not supported, attribute "+ldapAttributeNameFromSchema
+";"+option+" on "+entry.getDn());
}
if (attributeHandler != null) {
attributeHandler.handle(connection, entry, ldapAttribute, ab);
}
String connIdMapKey;
if (option == null) {
connIdMapKey = POLYSTRING_ORIG_KEY;
} else {
connIdMapKey = option.substring("lang-".length());
}
Value ldapValue = ldapAttribute.get();
Object connIdValue = toConnIdValue(connIdAttributeName, ldapValue, ldapAttributeNameFromSchema, ldapAttributeType);
if (connIdValue != null) {
connIdValueMap.put(connIdMapKey, connIdValue);
}
}
ab.addValue(connIdValueMap);
try {
return ab.build();
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(e.getMessage() + ", attribute "+connIdAttributeName+" (ldap: "+ldapAttributeNameFromSchema+")", e);
}
}
@Override
protected void extendConnectorObject(ConnectorObjectBuilder cob, Entry entry, String objectClassName) {
......
......@@ -320,12 +320,12 @@ public abstract class AbstractSchemaTranslator<C extends AbstractLdapConfigurati
// This is handled separately as __UID__ attribute
continue;
}
String icfAttributeName = toConnIdAttributeName(ldapAttribute.getName());
if (containsAttribute(attrInfoList, icfAttributeName)) {
String connIdAttributeName = toConnIdAttributeName(ldapAttribute.getName());
if (containsAttribute(attrInfoList, connIdAttributeName)) {
LOG.ok("Skipping translation of attribute {0} because it is already translated", ldapAttribute.getName());
continue;
}
AttributeInfoBuilder aib = new AttributeInfoBuilder(icfAttributeName);
AttributeInfoBuilder aib = new AttributeInfoBuilder(connIdAttributeName);
aib.setRequired(isRequired);
LdapSyntax ldapSyntax = getSyntax(ldapAttribute);
......@@ -333,16 +333,16 @@ public abstract class AbstractSchemaTranslator<C extends AbstractLdapConfigurati
LOG.warn("No syntax for attribute: {0}", ldapAttribute.getName());
}
Class<?> icfType = toConnIdType(ldapSyntax, icfAttributeName);
aib.setType(icfType);
aib.setSubtype(toConnIdSubtype(icfType, ldapAttribute, icfAttributeName));
Class<?> connIdType = toConnIdType(ldapSyntax, connIdAttributeName);
aib.setType(connIdType);
aib.setSubtype(toConnIdSubtype(connIdType, ldapAttribute, connIdAttributeName));
aib.setNativeName(ldapAttribute.getName());
if (isOperational(ldapAttribute)) {
aib.setReturnedByDefault(false);
}
setAttributeMultiplicityAndPermissions(ldapAttribute, icfAttributeName, aib);
LOG.ok("Translating {0} -> {1} ({2} -> {3})", ldapAttribute.getName(), icfAttributeName,
ldapSyntax==null?null:ldapSyntax.getOid(), icfType);
setAttributeMultiplicityAndPermissions(ldapAttribute, connIdAttributeName, aib);
LOG.ok("Translating {0} -> {1} ({2} -> {3})", ldapAttribute.getName(), connIdAttributeName,
ldapSyntax==null?null:ldapSyntax.getOid(), connIdType);
AttributeInfo attributeInfo = aib.build();
attrInfoList.put(attributeInfo.getName(), attributeInfo);
}
......@@ -445,8 +445,8 @@ public abstract class AbstractSchemaTranslator<C extends AbstractLdapConfigurati
return mutableLdapAttributeType;
}
public Class<?> toConnIdType(LdapSyntax syntax, String icfAttributeName) {
if (OperationalAttributeInfos.PASSWORD.is(icfAttributeName)) {
public Class<?> toConnIdType(LdapSyntax syntax, String connIdAttributeName) {
if (OperationalAttributeInfos.PASSWORD.is(connIdAttributeName)) {
return GuardedString.class;
}
if (syntax == null) {
......@@ -484,8 +484,8 @@ public abstract class AbstractSchemaTranslator<C extends AbstractLdapConfigurati
}
}
public String toConnIdSubtype(Class<?> icfType, AttributeType ldapAttribute, String icfAttributeName) {
if (OperationalAttributeInfos.PASSWORD.is(icfAttributeName)) {
public String toConnIdSubtype(Class<?> connIdType, AttributeType ldapAttribute, String connIdAttributeName) {
if (OperationalAttributeInfos.PASSWORD.is(connIdAttributeName)) {
return null;
}
if (ldapAttribute == null) {
......@@ -505,7 +505,7 @@ public abstract class AbstractSchemaTranslator<C extends AbstractLdapConfigurati
return null;
}
if (SYNTAX_MAP.get(syntaxOid) == null) {
if (icfType == String.class) {
if (connIdType == String.class) {
return AttributeInfo.Subtypes.STRING_CASE_IGNORE.toString();
} else {
return null;
......@@ -535,6 +535,14 @@ public abstract class AbstractSchemaTranslator<C extends AbstractLdapConfigurati
}
return false;
}
public boolean isPolyAttribute(AttributeType ldapAttributeType, List<Object> connIdValues) {
return false;
}
public boolean isPolyAttribute(AttributeInfo connIdAttributeInfo) {
return false;
}
public List<Value> toLdapValues(AttributeType ldapAttributeType, List<Object> icfAttributeValues) {
List<Value> ldapValues = new ArrayList<>(icfAttributeValues.size());
......@@ -544,6 +552,15 @@ public abstract class AbstractSchemaTranslator<C extends AbstractLdapConfigurati
return ldapValues;
}
/**
* Method to convert "poly" values, such as PolyString.
*
* @return map with attribute name as a key (with option) and list of values as value.
*/
public Map<String, List<Value>> toLdapPolyValues(AttributeType ldapAttributeType, List<Object> values) {
throw new UnsupportedOperationException("Poly-attributes are not supported (attribute '"+ldapAttributeType.getName()+"'");
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Value toLdapValue(AttributeType ldapAttributeType, Object icfAttributeValue) {
if (icfAttributeValue == null) {
......@@ -1018,6 +1035,16 @@ public abstract class AbstractSchemaTranslator<C extends AbstractLdapConfigurati
return toConnIdObject(connection, icfStructuralObjectClassInfo, entry, dn, null);
}
// TODO: use version from SchemaUtil
private AttributeInfo findAttributeInfo(ObjectClassInfo connIdObjectClassInfo, String connIdAttributeName) {
for (AttributeInfo attributeInfo: connIdObjectClassInfo.getAttributeInfo()) {
if (attributeInfo.is(connIdAttributeName)) {
return attributeInfo;
}
}
return null;
}
public ConnectorObject toConnIdObject(LdapNetworkConnection connection, ObjectClassInfo connIdStructuralObjectClassInfo, Entry entry, String dn, AttributeHandler attributeHandler) {
LdapObjectClasses ldapObjectClasses = processObjectClasses(entry);
if (connIdStructuralObjectClassInfo == null) {
......@@ -1060,59 +1087,185 @@ public abstract class AbstractSchemaTranslator<C extends AbstractLdapConfigurati
}
cob.setUid(uid);
Map<String,PolyAttributeStruct> polyAttributes = new HashMap<>();
Iterator<org.apache.directory.api.ldap.model.entry.Attribute> iterator = entry.iterator();
while (iterator.hasNext()) {
org.apache.directory.api.ldap.model.entry.Attribute ldapAttribute = iterator.next();
String ldapAttrName = getLdapAttributeName(ldapAttribute);
// LOG.ok("Processing attribute {0}", ldapAttrName);
LOG.ok("Processing attribute {0} (UP: {1})", ldapAttrName, ldapAttribute.getUpId());
if (!shouldTranslateAttribute(ldapAttrName)) {
// LOG.ok("Should not translate attribute {0}, skipping", ldapAttrName);
continue;
}
AttributeType attributeType = schemaManager.getAttributeType(ldapAttrName);
AttributeType ldapAttributeType = schemaManager.getAttributeType(ldapAttrName);
// LOG.ok("Type for attribute {0}: {1}", ldapAttrName, attributeType);
String ldapAttributeNameFromSchema = ldapAttrName;
if (attributeType == null) {
if (ldapAttributeType == null) {
if (!configuration.isAllowUnknownAttributes()) {
throw new InvalidAttributeValueException("Unknown LDAP attribute " + ldapAttrName + " (not present in LDAP schema)");
}
} else {
ldapAttributeNameFromSchema = attributeType.getName();
ldapAttributeNameFromSchema = ldapAttributeType.getName();
}
if (uidAttributeName.equals(ldapAttributeNameFromSchema)) {
continue;
}
Attribute connIdAttribute = toConnIdAttribute(connection, entry, ldapAttribute, attributeHandler);
// LOG.ok("ConnId attribute for {0}: {1}", ldapAttrName, icfAttribute);
if (connIdAttribute == null) {
PolyAttributeStruct polyStruct = polyAttributes.get(ldapAttributeNameFromSchema);
if (polyStruct != null) {
// We know that this attribute is poly. Just collect the data.
// And we can avoid the rest of the processing because it was done already.
polyStruct.addAttribute(ldapAttribute);
continue;
}
AttributeInfo attributeInfo = SchemaUtil.findAttributeInfo(connIdStructuralObjectClassInfo, connIdAttribute);
if (attributeInfo == null) {
String connIdAttributeName = toConnIdAttributeName(ldapAttributeNameFromSchema);
// TODO: use version of findAttributeInfo from SchemaUtil
AttributeInfo connIdAttributeInfo = findAttributeInfo(connIdStructuralObjectClassInfo, connIdAttributeName);
if (connIdAttributeInfo == null) {
for (ObjectClassInfo icfAuxiliaryObjectClassInfo: connIdAuxiliaryObjectClassInfos) {
attributeInfo = SchemaUtil.findAttributeInfo(icfAuxiliaryObjectClassInfo, connIdAttribute);
// TODO: use version of findAttributeInfo from SchemaUtil
connIdAttributeInfo = findAttributeInfo(icfAuxiliaryObjectClassInfo, connIdAttributeName);
// LOG.ok("Looking for ConnId attribute {0} info in auxiliary class {1}: {2}", icfAttribute, icfAuxiliaryObjectClassInfo==null?null:icfAuxiliaryObjectClassInfo.getType(), attributeInfo);
if (attributeInfo != null) {
if (connIdAttributeInfo != null) {
break;
}
// LOG.ok("Failed to find attribute in: {0}", icfAuxiliaryObjectClassInfo);
}
}
// LOG.ok("ConnId attribute info for {0} ({1}): {2}", icfAttribute.getName(), ldapAttrName, attributeInfo);
if (attributeInfo != null) {
// Avoid sending unknown attributes (such as createtimestamp)
cob.addAttribute(connIdAttribute);
if (connIdAttributeInfo == null) {
LOG.ok("ConnId attribute {0} is not part of ConnId schema, skipping", connIdAttributeName);
continue;
}
if (isPolyAttribute(connIdAttributeInfo)) {
// Defer processing poly attributes for later. We do not have all the values yet. Just collect the values now.
polyAttributes.put(ldapAttributeNameFromSchema, new PolyAttributeStruct(ldapAttributeType, connIdAttributeName, ldapAttribute));
} else {
LOG.ok("ConnId attribute {0} is not part of ConnId schema, skipping", connIdAttribute.getName());
// Process simple (non-poly) attributes right here. We are not waiting for anything else.
Attribute connIdAttribute = toConnIdAttribute(connIdAttributeName, ldapAttributeNameFromSchema, ldapAttributeType, ldapAttribute,
connection, entry, attributeHandler);
// LOG.ok("ConnId attribute for {0}: {1}", ldapAttrName, icfAttribute);
if (connIdAttribute != null) {
cob.addAttribute(connIdAttribute);
}
}
}
for (Map.Entry<String, PolyAttributeStruct> polyAttributesEntry : polyAttributes.entrySet()) {
String ldapAttributeNameFromSchema = polyAttributesEntry.getKey();
Attribute connIdAttribute = toConnIdAttributePoly(polyAttributesEntry.getValue().getConnIdAttributeName(), ldapAttributeNameFromSchema, polyAttributesEntry.getValue().getLdapAttributeType(),
polyAttributesEntry.getValue().getLdapAttributes(),
connection, entry, attributeHandler);
if (connIdAttribute != null) {
cob.addAttribute(connIdAttribute);
}
}
extendConnectorObject(cob, entry, connIdStructuralObjectClassInfo.getType());
return cob.build();
}
class PolyAttributeStruct {
private AttributeType ldapAttributeType;
private String connIdAttributeName;
private List<org.apache.directory.api.ldap.model.entry.Attribute> ldapAttributes = new ArrayList<>();