Skip to content

Commit

Permalink
When accepting data from resource, attribute names are matched case-i…
Browse files Browse the repository at this point in the history
…nsensitively (MID-2085).
  • Loading branch information
mederly committed Nov 13, 2014
1 parent a810e82 commit e777d2c
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 26 deletions.
Expand Up @@ -46,6 +46,7 @@ public class DummyConfiguration extends AbstractConfiguration {
private boolean caseIgnoreValues = false;
private boolean generateDefaultValues = false;
private boolean tolerateDuplicateValues = true;
private boolean varyLetterCase = false;
private String uselessString;
private GuardedString uselessGuardedString;

Expand Down Expand Up @@ -225,6 +226,16 @@ public GuardedString getUselessGuardedString() {
public void setUselessGuardedString(GuardedString uselessGuardedString) {
this.uselessGuardedString = uselessGuardedString;
}

@ConfigurationProperty(displayMessageKey = "UI_VARY_LETTER_CASE",
helpMessageKey = "UI_VARY_LETTER_CASE_HELP")
public boolean isVaryLetterCase() {
return varyLetterCase;
}

public void setVaryLetterCase(boolean value) {
this.varyLetterCase = value;
}

/**
* {@inheritDoc}
Expand Down
Expand Up @@ -15,7 +15,6 @@
*/
package com.evolveum.icf.dummy.connector;

import org.apache.commons.lang.StringUtils;
import org.identityconnectors.framework.spi.operations.*;
import org.identityconnectors.framework.common.exceptions.AlreadyExistsException;
import org.identityconnectors.framework.common.exceptions.ConnectionFailedException;
Expand Down Expand Up @@ -50,10 +49,8 @@
import org.identityconnectors.framework.common.objects.SyncResultsHandler;
import org.identityconnectors.framework.common.objects.SyncToken;
import org.identityconnectors.framework.common.objects.Uid;
import org.identityconnectors.framework.common.objects.filter.AbstractFilterTranslator;
import org.identityconnectors.framework.common.objects.filter.Filter;
import org.identityconnectors.framework.common.objects.filter.FilterTranslator;
import org.identityconnectors.framework.spi.AttributeNormalizer;
import org.identityconnectors.framework.spi.Configuration;
import org.identityconnectors.framework.spi.Connector;
import org.identityconnectors.framework.spi.ConnectorClass;
Expand All @@ -79,7 +76,6 @@
import com.evolveum.icf.dummy.resource.ObjectAlreadyExistsException;
import com.evolveum.icf.dummy.resource.ObjectDoesNotExistException;
import com.evolveum.icf.dummy.resource.SchemaViolationException;
import com.evolveum.icf.dummy.connector.Utils;

/**
* Connector for the Dummy Resource.
Expand Down Expand Up @@ -145,7 +141,7 @@ public void init(Configuration configuration) {
resource.setEnforceUniqueName(this.configuration.isEnforceUniqueName());
resource.setTolerateDuplicateValues(this.configuration.getTolerateDuplicateValues());
resource.setGenerateDefaultValues(this.configuration.isGenerateDefaultValues());

resource.setUselessString(this.configuration.getUselessString());
GuardedString uselessGuardedString = this.configuration.getUselessGuardedString();
if (uselessGuardedString == null) {
Expand Down Expand Up @@ -1051,6 +1047,9 @@ private ConnectorObjectBuilder createConnectorObjectBuilderCommon(DummyObject du
}
}
Set<Object> values = dummyObject.getAttributeValues(name, Object.class);
if (configuration.isVaryLetterCase()) {
name = varyLetterCase(name);
}
builder.addAttribute(name, values);
}

Expand All @@ -1072,7 +1071,21 @@ private ConnectorObjectBuilder createConnectorObjectBuilderCommon(DummyObject du

return builder;
}


private String varyLetterCase(String name) {
StringBuilder sb = new StringBuilder(name.length());
for (char c : name.toCharArray()) {
double a = Math.random();
if (a < 0.4) {
c = Character.toLowerCase(c);
} else if (a > 0.7) {
c = Character.toUpperCase(c);
}
sb.append(c);
}
return sb.toString();
}

private Long convertToLong(Date date) {
if (date == null) {
return null;
Expand Down
Expand Up @@ -349,11 +349,14 @@ public void setDynamic(boolean dynamic) {

@Override
public boolean isValidFor(QName elementQName, Class<? extends ItemDefinition> clazz) {
return refinedAttributeDefinition.isValidFor(elementQName, clazz);
return isValidFor(elementQName, clazz, false);
}

@Override
public boolean isValidFor(QName elementQName, Class<? extends ItemDefinition> clazz, boolean caseInsensitive) {
return refinedAttributeDefinition.isValidFor(elementQName, clazz, caseInsensitive);
}



public Boolean getReturnedByDefault() {
return refinedAttributeDefinition.getReturnedByDefault();
}
Expand Down
Expand Up @@ -194,8 +194,12 @@ public <C extends Containerable> PrismContainerDefinition<C> findContainerDefini
public <C extends Containerable> PrismContainerDefinition<C> findContainerDefinition(ItemPath path) {
return findItemDefinition(path, PrismContainerDefinition.class);
}

public <T extends ItemDefinition> T findItemDefinition(QName name, Class<T> clazz) {
return findItemDefinition(name, clazz, false);
}

public <T extends ItemDefinition> T findItemDefinition(QName name, Class<T> clazz, boolean caseInsensitive) {
if (clazz == null) {
throw new IllegalArgumentException("type not specified while searching for " + name + " in " + this);
}
Expand All @@ -204,7 +208,7 @@ public <T extends ItemDefinition> T findItemDefinition(QName name, Class<T> claz
}

for (ItemDefinition def : getDefinitions()) {
if (isItemValid(def, name, clazz)) {
if (isItemValid(def, name, clazz, caseInsensitive)) {
return (T) def;
}
}
Expand All @@ -227,11 +231,11 @@ public <T extends ItemDefinition> T findItemDefinition(ItemPath path, Class<T> c
return null;
}

private <T extends ItemDefinition> boolean isItemValid(ItemDefinition def, QName name, Class<T> clazz) {
private <T extends ItemDefinition> boolean isItemValid(ItemDefinition def, QName name, Class<T> clazz, boolean caseInsensitive) {
if (def == null) {
return false;
}
return def.isValidFor(name, clazz);
return def.isValidFor(name, clazz, caseInsensitive);
}

/**
Expand Down
Expand Up @@ -239,12 +239,16 @@ public void setCanAdd(boolean add) {
public boolean canAdd() {
return canAdd;
}

public boolean isValidFor(QName elementQName, Class<? extends ItemDefinition> clazz) {

public boolean isValidFor(QName elementQName, Class<? extends ItemDefinition> clazz) {
return isValidFor(elementQName, clazz, false);
}

public boolean isValidFor(QName elementQName, Class<? extends ItemDefinition> clazz, boolean caseInsensitive) {
if (!clazz.isAssignableFrom(this.getClass())) {
return false;
}
if (QNameUtil.match(elementQName, getName())) {
if (QNameUtil.match(elementQName, getName(), caseInsensitive)) {
return true;
}
return false;
Expand Down
Expand Up @@ -154,7 +154,11 @@ public void revive(PrismContext prismContext) {
}
}

public <D extends ItemDefinition> D findItemDefinition(QName name, Class<D> clazz) {
public <D extends ItemDefinition> D findItemDefinition(QName name, Class<D> clazz) {
return findItemDefinition(name, clazz, false);
}

public <D extends ItemDefinition> D findItemDefinition(QName name, Class<D> clazz, boolean caseInsensitive) {
if (clazz == null) {
throw new IllegalArgumentException("type not specified while searching for " + name + " in " + this);
}
Expand All @@ -167,7 +171,7 @@ public <D extends ItemDefinition> D findItemDefinition(QName name, Class<D> claz
return null;
}

return complexTypeDefinition.findItemDefinition(name, clazz);
return complexTypeDefinition.findItemDefinition(name, clazz, caseInsensitive);
}

public <T extends ItemDefinition> T findItemDefinition(ItemPath path, Class<T> clazz) {
Expand Down
Expand Up @@ -87,13 +87,18 @@ public void setComposite(boolean isComposite) {

@Override
public boolean isValidFor(QName elementQName, Class<? extends ItemDefinition> clazz) {
return isValidFor(elementQName, clazz, false);
}

@Override
public boolean isValidFor(QName elementQName, Class<? extends ItemDefinition> clazz, boolean caseInsensitive) {
if (!clazz.isAssignableFrom(this.getClass())) {
return false;
}
if (QNameUtil.match(elementQName, getName())) {
if (QNameUtil.match(elementQName, getName(), caseInsensitive)) {
return true;
}
if (QNameUtil.match(elementQName, getCompositeObjectElementName())) {
if (QNameUtil.match(elementQName, getCompositeObjectElementName(), caseInsensitive)) {
return true;
}
return false;
Expand Down
Expand Up @@ -314,13 +314,17 @@ protected void copyDefinitionData(ResourceAttributeContainerDefinition clone) {
// }

public ResourceAttributeDefinition findAttributeDefinition(QName elementQName) {
return findItemDefinition(elementQName, ResourceAttributeDefinition.class);
return findAttributeDefinition(elementQName, false);
}

public ResourceAttributeDefinition findAttributeDefinition(QName elementQName, boolean caseInsensitive) {
return findItemDefinition(elementQName, ResourceAttributeDefinition.class, caseInsensitive);
}

public ResourceAttributeDefinition findAttributeDefinition(ItemPath elementPath) {
return findItemDefinition(elementPath, ResourceAttributeDefinition.class);
}

public ResourceAttributeDefinition findAttributeDefinition(String elementLocalname) {
QName elementQName = new QName(getName().getNamespaceURI(),elementLocalname);
return findAttributeDefinition(elementQName);
Expand Down
25 changes: 22 additions & 3 deletions infra/util/src/main/java/com/evolveum/midpoint/util/QNameUtil.java
Expand Up @@ -85,17 +85,36 @@ public static boolean compareQName(QName qname, Node node) {
* Matching with considering wildcard namespace (null).
*/
public static boolean match(QName a, QName b) {
return match(a, b, false);
}

// case insensitive is related to local parts
public static boolean match(QName a, QName b, boolean caseInsensitive) {
if (a == null && b == null) {
return true;
}
if (a == null || b == null) {
return false;
}
if (StringUtils.isBlank(a.getNamespaceURI()) || StringUtils.isBlank(b.getNamespaceURI())) {
return a.getLocalPart().equals(b.getLocalPart());
if (!caseInsensitive) {
// traditional comparison
if (StringUtils.isBlank(a.getNamespaceURI()) || StringUtils.isBlank(b.getNamespaceURI())) {
return a.getLocalPart().equals(b.getLocalPart());
} else {
return a.equals(b);
}
} else {
return a.equals(b);
// relaxed (case-insensitive) one
if (!a.getLocalPart().equalsIgnoreCase(b.getLocalPart())) {
return false;
}
if (StringUtils.isBlank(a.getNamespaceURI()) || StringUtils.isBlank(b.getNamespaceURI())) {
return true;
} else {
return a.getNamespaceURI().equals(b.getNamespaceURI());
}
}

}

public static QName resolveNs(QName a, Collection<QName> col){
Expand Down
Expand Up @@ -49,6 +49,7 @@
<clearValue>whatever</clearValue>
</icfi:uselessGuardedString>
<icfi:uselessString>USEless</icfi:uselessString>
<icfi:varyLetterCase>true</icfi:varyLetterCase>
</icfc:configurationProperties>

</connectorConfiguration>
Expand Down
Expand Up @@ -187,12 +187,14 @@ <T extends ShadowType> PrismObject<T> convertToResourceObject(ConnectorObject co
}

QName qname = icfNameMapper.convertAttributeNameToQName(icfAttr.getName(), resourceSchemaNamespace);
ResourceAttributeDefinition attributeDefinition = attributesContainerDefinition.findAttributeDefinition(qname);
ResourceAttributeDefinition attributeDefinition = attributesContainerDefinition.findAttributeDefinition(qname, true); // TODO configure whether we want the case insensitivity!

if (attributeDefinition == null) {
throw new SchemaException("Unknown attribute "+qname+" in definition of object class "+attributesContainerDefinition.getTypeName()+". Original ICF name: "+icfAttr.getName(), qname);
}

qname = attributeDefinition.getName(); // normalized version

ResourceAttribute<Object> resourceAttribute = attributeDefinition.instantiate(qname);

// if true, we need to convert whole connector object to the
Expand Down

0 comments on commit e777d2c

Please sign in to comment.