/*
* Copyright (c) 2010-2016 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package 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;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.identityconnectors.framework.common.exceptions.ConnectorIOException;
import org.identityconnectors.framework.common.exceptions.InvalidAttributeValueException;
import org.identityconnectors.framework.common.exceptions.UnknownUidException;
import org.identityconnectors.framework.common.objects.*;
import static com.evolveum.icf.dummy.connector.Utils.*;
import java.io.FileNotFoundException;
import java.net.ConnectException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.common.security.GuardedString.Accessor;
import org.identityconnectors.framework.common.objects.filter.AndFilter;
import org.identityconnectors.framework.common.objects.filter.AttributeFilter;
import org.identityconnectors.framework.common.objects.filter.ContainsAllValuesFilter;
import org.identityconnectors.framework.common.objects.filter.ContainsFilter;
import org.identityconnectors.framework.common.objects.filter.EndsWithFilter;
import org.identityconnectors.framework.common.objects.filter.EqualsFilter;
import org.identityconnectors.framework.common.objects.filter.Filter;
import org.identityconnectors.framework.common.objects.filter.FilterTranslator;
import org.identityconnectors.framework.common.objects.filter.FilterVisitor;
import org.identityconnectors.framework.common.objects.filter.GreaterThanFilter;
import org.identityconnectors.framework.common.objects.filter.GreaterThanOrEqualFilter;
import org.identityconnectors.framework.common.objects.filter.LessThanFilter;
import org.identityconnectors.framework.common.objects.filter.LessThanOrEqualFilter;
import org.identityconnectors.framework.common.objects.filter.NotFilter;
import org.identityconnectors.framework.common.objects.filter.OrFilter;
import org.identityconnectors.framework.common.objects.filter.StartsWithFilter;
import org.identityconnectors.framework.spi.Configuration;
import org.identityconnectors.framework.spi.Connector;
import org.identityconnectors.framework.spi.ConnectorClass;
import org.identityconnectors.framework.spi.PoolableConnector;
import com.evolveum.icf.dummy.resource.ConflictException;
import com.evolveum.icf.dummy.resource.DummyAccount;
import com.evolveum.icf.dummy.resource.DummyAttributeDefinition;
import com.evolveum.icf.dummy.resource.DummyDelta;
import com.evolveum.icf.dummy.resource.DummyDeltaType;
import com.evolveum.icf.dummy.resource.DummyGroup;
import com.evolveum.icf.dummy.resource.DummyObject;
import com.evolveum.icf.dummy.resource.DummyObjectClass;
import com.evolveum.icf.dummy.resource.DummyOrg;
import com.evolveum.icf.dummy.resource.DummyPrivilege;
import com.evolveum.icf.dummy.resource.DummyResource;
import com.evolveum.icf.dummy.resource.DummySyncStyle;
import com.evolveum.icf.dummy.resource.ObjectAlreadyExistsException;
import com.evolveum.icf.dummy.resource.ObjectDoesNotExistException;
import com.evolveum.icf.dummy.resource.SchemaViolationException;
/**
* Connector for the Dummy Resource.
*
* Dummy resource is a simple Java object that pretends to be a resource. It has accounts and
* account schema. It has operations to manipulate accounts, execute scripts and so on
* almost like a real resource. The purpose is to simulate a real resource with a very
* little overhead. This connector connects the Dummy resource to ICF.
*
* @see DummyResource
*
*/
@ConnectorClass(displayNameKey = "UI_CONNECTOR_NAME",
configurationClass = DummyConfiguration.class)
public class DummyConnector implements PoolableConnector, AuthenticateOp, ResolveUsernameOp, CreateOp, DeleteOp, SchemaOp,
ScriptOnConnectorOp, ScriptOnResourceOp, SearchOp<Filter>, SyncOp, TestOp, UpdateAttributeValuesOp {
// We want to see if the ICF framework logging works properly
private static final Log log = Log.getLog(DummyConnector.class);
// We also want to see if the libraries that use JUL are logging properly
private static final java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(DummyConnector.class.getName());
// Marker used in logging tests
public static final String LOG_MARKER = "_M_A_R_K_E_R_";
private static final String OBJECTCLASS_ACCOUNT_NAME = "account";
private static final String OBJECTCLASS_GROUP_NAME = "group";
private static final String OBJECTCLASS_PRIVILEGE_NAME = "privilege";
private static final String OBJECTCLASS_ORG_NAME = "org";
/**
* Place holder for the {@link Configuration} passed into the init() method
*/
private DummyConfiguration configuration;
private DummyResource resource;
private static String staticVal;
/**
* Gets the Configuration context for this connector.
*/
@Override
public Configuration getConfiguration() {
return this.configuration;
}
/**
* Callback method to receive the {@link Configuration}.
*
* @see Connector#init(org.identityconnectors.framework.spi.Configuration)
*/
@Override
public void init(Configuration configuration) {
notNullArgument(configuration, "configuration");
this.configuration = (DummyConfiguration) configuration;
String instanceName = this.configuration.getInstanceId();
if (instanceName == null || instanceName.isEmpty()) {
instanceName = null;
}
resource = DummyResource.getInstance(instanceName);
resource.setCaseIgnoreId(this.configuration.getCaseIgnoreId());
resource.setCaseIgnoreValues(this.configuration.getCaseIgnoreValues());
resource.setEnforceUniqueName(this.configuration.isEnforceUniqueName());
resource.setTolerateDuplicateValues(this.configuration.getTolerateDuplicateValues());
resource.setGenerateDefaultValues(this.configuration.isGenerateDefaultValues());
resource.setGenerateAccountDescriptionOnCreate(this.configuration.getGenerateAccountDescriptionOnCreate());
resource.setGenerateAccountDescriptionOnUpdate(this.configuration.getGenerateAccountDescriptionOnUpdate());
if (this.configuration.getForbiddenNames().length > 0) {
resource.setForbiddenNames(Arrays.asList(((DummyConfiguration) configuration).getForbiddenNames()));
} else {
resource.setForbiddenNames(null);
}
resource.setUselessString(this.configuration.getUselessString());
GuardedString uselessGuardedString = this.configuration.getUselessGuardedString();
if (uselessGuardedString == null) {
resource.setUselessGuardedString(null);
} else {
uselessGuardedString.access(chars -> resource.setUselessGuardedString(new String(chars)));
}
resource.setMonsterization(this.configuration.isMonsterized());
resource.connect();
if (staticVal == null) {
staticVal = this.toString();
}
log.info("Connected to dummy resource instance {0} ({1} connections open)", resource, resource.getConnectionCount());
}
/**
* Disposes of the connector's resources.
*
* @see Connector#dispose()
*/
public void dispose() {
resource.disconnect();
log.info("Disconnected from dummy resource instance {0} ({1} connections still open)", resource, resource.getConnectionCount());
}
@Override
public void checkAlive() {
// notthig to do. always alive.
}
/******************
* SPI Operations
*
* Implement the following operations using the contract and
* description found in the Javadoc for these methods.
******************/
/**
* {@inheritDoc}
*/
/**
* {@inheritDoc}
*/
public Uid create(final ObjectClass objectClass, final Set<Attribute> createAttributes, final OperationOptions options) {
log.info("create::begin attributes {0}", createAttributes);
validate(objectClass);
DummyObject newObject;
try {
if (ObjectClass.ACCOUNT.is(objectClass.getObjectClassValue())) {
// Convert attributes to account
DummyAccount newAccount = convertToAccount(createAttributes);
log.ok("Adding dummy account:\n{0}", newAccount.debugDump());
resource.addAccount(newAccount);
newObject = newAccount;
} else if (ObjectClass.GROUP.is(objectClass.getObjectClassValue())) {
DummyGroup newGroup = convertToGroup(createAttributes);
log.ok("Adding dummy group:\n{0}", newGroup.debugDump());
resource.addGroup(newGroup);
newObject = newGroup;
} else if (objectClass.is(OBJECTCLASS_PRIVILEGE_NAME)) {
DummyPrivilege newPriv = convertToPriv(createAttributes);
log.ok("Adding dummy privilege:\n{0}", newPriv.debugDump());
resource.addPrivilege(newPriv);
newObject = newPriv;
} else if (objectClass.is(OBJECTCLASS_ORG_NAME)) {
DummyOrg newOrg = convertToOrg(createAttributes);
log.ok("Adding dummy org:\n{0}", newOrg.debugDump());
resource.addOrg(newOrg);
newObject = newOrg;
} else {
throw new ConnectorException("Unknown object class "+objectClass);
}
} catch (ObjectAlreadyExistsException e) {
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new AlreadyExistsException(e.getMessage(),e);
} catch (ConnectException e) {
throw new ConnectionFailedException(e.getMessage(), e);
} catch (FileNotFoundException e) {
throw new ConnectorIOException(e.getMessage(), e);
} catch (SchemaViolationException e) {
throw new InvalidAttributeValueException(e);
} catch (ConflictException e) {
throw new AlreadyExistsException(e);
}
String id;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
id = newObject.getName();
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
id = newObject.getId();
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
Uid uid = new Uid(id);
log.info("create::end");
return uid;
}
/**
* {@inheritDoc}
*/
public Uid update(ObjectClass objectClass, Uid uid, Set<Attribute> replaceAttributes, OperationOptions options) {
log.info("update::begin");
validate(objectClass);
validate(uid);
try {
if (ObjectClass.ACCOUNT.is(objectClass.getObjectClassValue())) {
final DummyAccount account;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
account = resource.getAccountByUsername(uid.getUidValue(), false);
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
account = resource.getAccountById(uid.getUidValue(), false);
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (account == null) {
throw new UnknownUidException("Account with UID "+uid+" does not exist on resource");
}
// we do this before setting attribute values, in case when description itself would be changed
resource.changeDescriptionIfNeeded(account);
for (Attribute attr : replaceAttributes) {
if (attr.is(Name.NAME)) {
String newName = (String)attr.getValue().get(0);
try {
resource.renameAccount(account.getId(), account.getName(), newName);
} catch (ObjectDoesNotExistException e) {
throw new org.identityconnectors.framework.common.exceptions.UnknownUidException(e.getMessage(), e);
} catch (ObjectAlreadyExistsException e) {
throw new org.identityconnectors.framework.common.exceptions.AlreadyExistsException(e.getMessage(), e);
} catch (SchemaViolationException e) {
throw new org.identityconnectors.framework.common.exceptions.ConnectorException("Schema exception: " + e.getMessage(), e);
}
// We need to change the returned uid here (only if the mode is not set to UUID)
if (!(configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID))){
uid = new Uid(newName);
}
} else if (attr.is(OperationalAttributes.PASSWORD_NAME)) {
changePassword(account,attr);
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
account.setEnabled(getBoolean(attr));
} else if (attr.is(OperationalAttributes.ENABLE_DATE_NAME)) {
account.setValidFrom(getDate(attr));
} else if (attr.is(OperationalAttributes.DISABLE_DATE_NAME)) {
account.setValidTo(getDate(attr));
} else if (attr.is(OperationalAttributes.LOCK_OUT_NAME)) {
account.setLockout(getBooleanNotNull(attr));
} else if (PredefinedAttributes.AUXILIARY_OBJECT_CLASS_NAME.equalsIgnoreCase(attr.getName())) {
account.replaceAuxiliaryObjectClassNames(attr.getValue());
} else {
String name = attr.getName();
try {
account.replaceAttributeValues(name, attr.getValue());
} catch (SchemaViolationException e) {
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new InvalidAttributeValueException(e.getMessage(),e);
}
}
}
} else if (ObjectClass.GROUP.is(objectClass.getObjectClassValue())) {
final DummyGroup group;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
group = resource.getGroupByName(uid.getUidValue(), false);
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
group = resource.getGroupById(uid.getUidValue(), false);
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (group == null) {
throw new UnknownUidException("Group with UID "+uid+" does not exist on resource");
}
for (Attribute attr : replaceAttributes) {
if (attr.is(Name.NAME)) {
String newName = (String)attr.getValue().get(0);
try {
resource.renameGroup(group.getId(), group.getName(), newName);
} catch (ObjectDoesNotExistException e) {
throw new org.identityconnectors.framework.common.exceptions.UnknownUidException(e.getMessage(), e);
} catch (ObjectAlreadyExistsException e) {
throw new org.identityconnectors.framework.common.exceptions.AlreadyExistsException(e.getMessage(), e);
}
// We need to change the returned uid here
uid = new Uid(newName);
} else if (attr.is(OperationalAttributes.PASSWORD_NAME)) {
throw new IllegalArgumentException("Attempt to change password on group");
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
group.setEnabled(getBooleanNotNull(attr));
} else {
String name = attr.getName();
List<Object> values = attr.getValue();
if (attr.is(DummyGroup.ATTR_MEMBERS_NAME) && values != null && configuration.getUpCaseName()) {
List<Object> newValues = new ArrayList<Object>(values.size());
for (Object val: values) {
newValues.add(StringUtils.upperCase((String)val));
}
values = newValues;
}
try {
group.replaceAttributeValues(name, values);
} catch (SchemaViolationException e) {
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else if (objectClass.is(OBJECTCLASS_PRIVILEGE_NAME)) {
final DummyPrivilege priv;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
priv = resource.getPrivilegeByName(uid.getUidValue(), false);
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
priv = resource.getPrivilegeById(uid.getUidValue(), false);
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (priv == null) {
throw new UnknownUidException("Privilege with UID "+uid+" does not exist on resource");
}
for (Attribute attr : replaceAttributes) {
if (attr.is(Name.NAME)) {
String newName = (String)attr.getValue().get(0);
try {
resource.renamePrivilege(priv.getId(), priv.getName(), newName);
} catch (ObjectDoesNotExistException e) {
throw new org.identityconnectors.framework.common.exceptions.UnknownUidException(e.getMessage(), e);
} catch (ObjectAlreadyExistsException e) {
throw new org.identityconnectors.framework.common.exceptions.AlreadyExistsException(e.getMessage(), e);
}
// We need to change the returned uid here
uid = new Uid(newName);
} else if (attr.is(OperationalAttributes.PASSWORD_NAME)) {
throw new IllegalArgumentException("Attempt to change password on privilege");
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
throw new IllegalArgumentException("Attempt to change enable on privilege");
} else {
String name = attr.getName();
try {
priv.replaceAttributeValues(name, attr.getValue());
} catch (SchemaViolationException e) {
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else if (objectClass.is(OBJECTCLASS_ORG_NAME)) {
final DummyOrg org;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
org = resource.getOrgByName(uid.getUidValue(), false);
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
org = resource.getOrgById(uid.getUidValue(), false);
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (org == null) {
throw new UnknownUidException("Org with UID "+uid+" does not exist on resource");
}
for (Attribute attr : replaceAttributes) {
if (attr.is(Name.NAME)) {
String newName = (String)attr.getValue().get(0);
try {
resource.renameOrg(org.getId(), org.getName(), newName);
} catch (ObjectDoesNotExistException e) {
throw new org.identityconnectors.framework.common.exceptions.UnknownUidException(e.getMessage(), e);
} catch (ObjectAlreadyExistsException e) {
throw new org.identityconnectors.framework.common.exceptions.AlreadyExistsException(e.getMessage(), e);
}
// We need to change the returned uid here
uid = new Uid(newName);
} else if (attr.is(OperationalAttributes.PASSWORD_NAME)) {
throw new IllegalArgumentException("Attempt to change password on org");
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
throw new IllegalArgumentException("Attempt to change enable on org");
} else {
String name = attr.getName();
try {
org.replaceAttributeValues(name, attr.getValue());
} catch (SchemaViolationException e) {
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else {
throw new ConnectorException("Unknown object class "+objectClass);
}
} catch (ConnectException e) {
log.info("update::exception "+e);
throw new ConnectionFailedException(e.getMessage(), e);
} catch (FileNotFoundException e) {
log.info("update::exception "+e);
throw new ConnectorIOException(e.getMessage(), e);
} catch (SchemaViolationException e) {
log.info("update::exception "+e);
throw new InvalidAttributeValueException(e.getMessage(), e);
} catch (ConflictException e) {
log.info("update::exception "+e);
throw new AlreadyExistsException(e);
}
log.info("update::end");
return uid;
}
/**
* {@inheritDoc}
*/
public Uid addAttributeValues(ObjectClass objectClass, Uid uid, Set<Attribute> valuesToAdd, OperationOptions options) {
validate(objectClass);
validate(uid);
try {
if (ObjectClass.ACCOUNT.is(objectClass.getObjectClassValue())) {
DummyAccount account;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
account = resource.getAccountByUsername(uid.getUidValue());
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
account = resource.getAccountById(uid.getUidValue());
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (account == null) {
throw new UnknownUidException("Account with UID "+uid+" does not exist on resource");
}
// we could change the description here, but don't do that not to collide with ADD operation
// TODO add the functionality if needed
for (Attribute attr : valuesToAdd) {
if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
if (account.getPassword() != null) {
throw new IllegalArgumentException("Attempt to add value for password while password is already set");
}
changePassword(account,attr);
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
throw new IllegalArgumentException("Attempt to add value for enable attribute");
} else if (PredefinedAttributes.AUXILIARY_OBJECT_CLASS_NAME.equalsIgnoreCase(attr.getName())) {
account.addAuxiliaryObjectClassNames(attr.getValue());
} else {
String name = attr.getName();
try {
account.addAttributeValues(name, attr.getValue());
log.ok("Added attribute {0} values {1} from {2}, resulting values: {3}",
name, attr.getValue(), account, account.getAttributeValues(name, Object.class));
} catch (SchemaViolationException e) {
// we cannot throw checked exceptions. But this one looks suitable.
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else if (ObjectClass.GROUP.is(objectClass.getObjectClassValue())) {
DummyGroup group;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
group = resource.getGroupByName(uid.getUidValue());
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
group = resource.getGroupById(uid.getUidValue());
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (group == null) {
throw new UnknownUidException("Group with UID "+uid+" does not exist on resource");
}
for (Attribute attr : valuesToAdd) {
if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
throw new IllegalArgumentException("Attempt to change password on group");
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
throw new IllegalArgumentException("Attempt to add value for enable attribute");
} else {
String name = attr.getName();
List<Object> values = attr.getValue();
if (attr.is(DummyGroup.ATTR_MEMBERS_NAME) && values != null && configuration.getUpCaseName()) {
List<Object> newValues = new ArrayList<Object>(values.size());
for (Object val: values) {
newValues.add(StringUtils.upperCase((String)val));
}
values = newValues;
}
try {
group.addAttributeValues(name, values);
log.ok("Added attribute {0} values {1} from {2}, resulting values: {3}",
name, attr.getValue(), group, group.getAttributeValues(name, Object.class));
} catch (SchemaViolationException e) {
// we cannot throw checked exceptions. But this one looks suitable.
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else if (objectClass.is(OBJECTCLASS_PRIVILEGE_NAME)) {
DummyPrivilege priv;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
priv = resource.getPrivilegeByName(uid.getUidValue());
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
priv = resource.getPrivilegeById(uid.getUidValue());
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (priv == null) {
throw new UnknownUidException("Privilege with UID "+uid+" does not exist on resource");
}
for (Attribute attr : valuesToAdd) {
if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
throw new IllegalArgumentException("Attempt to change password on privilege");
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
throw new IllegalArgumentException("Attempt to add value for enable attribute");
} else {
String name = attr.getName();
try {
priv.addAttributeValues(name, attr.getValue());
log.ok("Added attribute {0} values {1} from {2}, resulting values: {3}",
name, attr.getValue(), priv, priv.getAttributeValues(name, Object.class));
} catch (SchemaViolationException e) {
// we cannot throw checked exceptions. But this one looks suitable.
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else if (objectClass.is(OBJECTCLASS_ORG_NAME)) {
DummyOrg org;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
org = resource.getOrgByName(uid.getUidValue());
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
org = resource.getOrgById(uid.getUidValue());
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (org == null) {
throw new UnknownUidException("Org with UID "+uid+" does not exist on resource");
}
for (Attribute attr : valuesToAdd) {
if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
throw new IllegalArgumentException("Attempt to change password on org");
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
throw new IllegalArgumentException("Attempt to add value for enable org");
} else {
String name = attr.getName();
try {
org.addAttributeValues(name, attr.getValue());
log.ok("Added attribute {0} values {1} from {2}, resulting values: {3}",
name, attr.getValue(), org, org.getAttributeValues(name, Object.class));
} catch (SchemaViolationException e) {
// we cannot throw checked exceptions. But this one looks suitable.
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else {
throw new ConnectorException("Unknown object class "+objectClass);
}
} catch (ConnectException e) {
log.info("addAttributeValues::exception "+e);
throw new ConnectionFailedException(e.getMessage(), e);
} catch (FileNotFoundException e) {
log.info("addAttributeValues::exception "+e);
throw new ConnectorIOException(e.getMessage(), e);
} catch (SchemaViolationException e) {
log.info("addAttributeValues::exception "+e);
throw new InvalidAttributeValueException(e.getMessage(), e);
} catch (ConflictException e) {
log.info("addAttributeValues::exception "+e);
throw new AlreadyExistsException(e);
}
return uid;
}
/**
* {@inheritDoc}
*/
public Uid removeAttributeValues(ObjectClass objectClass, Uid uid, Set<Attribute> valuesToRemove, OperationOptions options) {
validate(objectClass);
validate(uid);
try {
if (ObjectClass.ACCOUNT.is(objectClass.getObjectClassValue())) {
DummyAccount account;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
account = resource.getAccountByUsername(uid.getUidValue());
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
account = resource.getAccountById(uid.getUidValue());
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (account == null) {
throw new UnknownUidException("Account with UID "+uid+" does not exist on resource");
}
// we could change the description here, but don't do that not to collide with REMOVE operation
// TODO add the functionality if needed
for (Attribute attr : valuesToRemove) {
if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
throw new UnsupportedOperationException("Removing password value is not supported");
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
throw new IllegalArgumentException("Attempt to remove value from enable attribute");
} else if (PredefinedAttributes.AUXILIARY_OBJECT_CLASS_NAME.equalsIgnoreCase(attr.getName())) {
account.deleteAuxiliaryObjectClassNames(attr.getValue());
} else {
String name = attr.getName();
try {
account.removeAttributeValues(name, attr.getValue());
log.ok("Removed attribute {0} values {1} from {2}, resulting values: {3}",
name, attr.getValue(), account, account.getAttributeValues(name, Object.class));
} catch (SchemaViolationException e) {
// we cannot throw checked exceptions. But this one looks suitable.
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else if (ObjectClass.GROUP.is(objectClass.getObjectClassValue())) {
DummyGroup group;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
group = resource.getGroupByName(uid.getUidValue());
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
group = resource.getGroupById(uid.getUidValue());
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (group == null) {
throw new UnknownUidException("Group with UID "+uid+" does not exist on resource");
}
for (Attribute attr : valuesToRemove) {
if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
throw new IllegalArgumentException("Attempt to change password on group");
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
throw new IllegalArgumentException("Attempt to remove value from enable attribute");
} else {
String name = attr.getName();
List<Object> values = attr.getValue();
if (attr.is(DummyGroup.ATTR_MEMBERS_NAME) && values != null && configuration.getUpCaseName()) {
List<Object> newValues = new ArrayList<Object>(values.size());
for (Object val: values) {
newValues.add(StringUtils.upperCase((String)val));
}
values = newValues;
}
try {
group.removeAttributeValues(name, values);
log.ok("Removed attribute {0} values {1} from {2}, resulting values: {3}",
name, attr.getValue(), group, group.getAttributeValues(name, Object.class));
} catch (SchemaViolationException e) {
// we cannot throw checked exceptions. But this one looks suitable.
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else if (objectClass.is(OBJECTCLASS_PRIVILEGE_NAME)) {
DummyPrivilege priv;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
priv = resource.getPrivilegeByName(uid.getUidValue());
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
priv = resource.getPrivilegeById(uid.getUidValue());
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (priv == null) {
throw new UnknownUidException("Privilege with UID "+uid+" does not exist on resource");
}
for (Attribute attr : valuesToRemove) {
if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
throw new IllegalArgumentException("Attempt to change password on privilege");
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
throw new IllegalArgumentException("Attempt to remove value from enable attribute");
} else {
String name = attr.getName();
try {
priv.removeAttributeValues(name, attr.getValue());
log.ok("Removed attribute {0} values {1} from {2}, resulting values: {3}",
name, attr.getValue(), priv, priv.getAttributeValues(name, Object.class));
} catch (SchemaViolationException e) {
// we cannot throw checked exceptions. But this one looks suitable.
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else if (objectClass.is(OBJECTCLASS_ORG_NAME)) {
DummyOrg org;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
org = resource.getOrgByName(uid.getUidValue());
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
org = resource.getOrgById(uid.getUidValue());
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
if (org == null) {
throw new UnknownUidException("Org with UID "+uid+" does not exist on resource");
}
for (Attribute attr : valuesToRemove) {
if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
throw new IllegalArgumentException("Attempt to change password on org");
} else if (attr.is(OperationalAttributes.ENABLE_NAME)) {
throw new IllegalArgumentException("Attempt to remove value from enable org");
} else {
String name = attr.getName();
try {
org.removeAttributeValues(name, attr.getValue());
log.ok("Removed attribute {0} values {1} from {2}, resulting values: {3}",
name, attr.getValue(), org, org.getAttributeValues(name, Object.class));
} catch (SchemaViolationException e) {
// we cannot throw checked exceptions. But this one looks suitable.
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
} else {
throw new ConnectorException("Unknown object class "+objectClass);
}
} catch (ConnectException e) {
log.info("removeAttributeValues::exception "+e);
throw new ConnectionFailedException(e.getMessage(), e);
} catch (FileNotFoundException e) {
log.info("removeAttributeValues::exception "+e);
throw new ConnectorIOException(e.getMessage(), e);
} catch (SchemaViolationException e) {
log.info("removeAttributeValues::exception "+e);
throw new InvalidAttributeValueException(e.getMessage(), e);
} catch (ConflictException e) {
log.info("removeAttributeValues::exception "+e);
throw new AlreadyExistsException(e);
}
return uid;
}
/**
* {@inheritDoc}
*/
public void delete(final ObjectClass objectClass, final Uid uid, final OperationOptions options) {
log.info("delete::begin");
validate(objectClass);
validate(uid);
String id = uid.getUidValue();
try {
if (ObjectClass.ACCOUNT.is(objectClass.getObjectClassValue())) {
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
resource.deleteAccountByName(id);
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
resource.deleteAccountById(id);
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
} else if (ObjectClass.GROUP.is(objectClass.getObjectClassValue())) {
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
resource.deleteGroupByName(id);
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
resource.deleteGroupById(id);
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
} else if (objectClass.is(OBJECTCLASS_PRIVILEGE_NAME)) {
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
resource.deletePrivilegeByName(id);
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
resource.deletePrivilegeById(id);
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
} else if (objectClass.is(OBJECTCLASS_ORG_NAME)) {
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
resource.deleteOrgByName(id);
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
resource.deleteOrgById(id);
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
} else {
throw new ConnectorException("Unknown object class "+objectClass);
}
} catch (ObjectDoesNotExistException e) {
// we cannot throw checked exceptions. But this one looks suitable.
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new UnknownUidException(e.getMessage(),e);
} catch (ConnectException e) {
log.info("delete::exception "+e);
throw new ConnectionFailedException(e.getMessage(), e);
} catch (FileNotFoundException e) {
log.info("delete::exception "+e);
throw new ConnectorIOException(e.getMessage(), e);
} catch (SchemaViolationException e) {
log.info("delete::exception "+e);
throw new InvalidAttributeValueException(e.getMessage(), e);
} catch (ConflictException e) {
log.info("delete::exception "+e);
throw new AlreadyExistsException(e);
}
log.info("delete::end");
}
/**
* {@inheritDoc}
*/
public Schema schema() {
log.info("schema::begin");
if (!configuration.getSupportSchema()) {
log.info("schema::unsupported operation");
throw new UnsupportedOperationException();
}
SchemaBuilder builder = new SchemaBuilder(DummyConnector.class);
try {
builder.defineObjectClass(createAccountObjectClass(configuration.getSupportActivation()));
builder.defineObjectClass(createGroupObjectClass(configuration.getSupportActivation()));
builder.defineObjectClass(createPrivilegeObjectClass());
builder.defineObjectClass(createOrgObjectClass());
for (ObjectClassInfo auxObjectClass : createAuxiliaryObjectClasses()) {
builder.defineObjectClass(auxObjectClass);
}
} catch (SchemaViolationException e) {
throw new InvalidAttributeValueException(e.getMessage(), e);
} catch (ConflictException e) {
throw new AlreadyExistsException(e);
}
if (configuration.isSupportReturnDefaultAttributes()) {
builder.defineOperationOption(OperationOptionInfoBuilder.buildReturnDefaultAttributes(), SearchOp.class,
SyncOp.class);
}
log.info("schema::end");
return builder.build();
}
private String getAccountObjectClassName() {
if (configuration.getUseLegacySchema()) {
return ObjectClass.ACCOUNT_NAME;
} else {
return OBJECTCLASS_ACCOUNT_NAME;
}
}
private String getGroupObjectClassName() {
if (configuration.getUseLegacySchema()) {
return ObjectClass.GROUP_NAME;
} else {
return OBJECTCLASS_GROUP_NAME;
}
}
private ObjectClassInfoBuilder createCommonObjectClassBuilder(String typeName,
DummyObjectClass dummyAccountObjectClass, boolean supportsActivation) {
ObjectClassInfoBuilder objClassBuilder = new ObjectClassInfoBuilder();
if (typeName != null) {
objClassBuilder.setType(typeName);
}
buildAttributes(objClassBuilder, dummyAccountObjectClass);
if (supportsActivation) {
// __ENABLE__ attribute
objClassBuilder.addAttributeInfo(OperationalAttributeInfos.ENABLE);
if (configuration.getSupportValidity()) {
objClassBuilder.addAttributeInfo(OperationalAttributeInfos.ENABLE_DATE);
objClassBuilder.addAttributeInfo(OperationalAttributeInfos.DISABLE_DATE);
}
objClassBuilder.addAttributeInfo(OperationalAttributeInfos.LOCK_OUT);
}
if (configuration.isAddConnectorStateAttributes()) {
objClassBuilder.addAttributeInfo(AttributeInfoBuilder.build(DummyResource.ATTRIBUTE_CONNECTOR_TO_STRING, String.class));
objClassBuilder.addAttributeInfo(AttributeInfoBuilder.build(DummyResource.ATTRIBUTE_CONNECTOR_STATIC_VAL, String.class));
objClassBuilder.addAttributeInfo(AttributeInfoBuilder.build(DummyResource.ATTRIBUTE_CONNECTOR_CONFIGURATION_TO_STRING, String.class));
}
// __NAME__ will be added by default
return objClassBuilder;
}
private ObjectClassInfo createAccountObjectClass(boolean supportsActivation) throws SchemaViolationException, ConflictException {
// __ACCOUNT__ objectclass
DummyObjectClass dummyAccountObjectClass;
try {
dummyAccountObjectClass = resource.getAccountObjectClass();
} catch (ConnectException e) {
throw new ConnectionFailedException(e.getMessage(), e);
} catch (FileNotFoundException e) {
throw new ConnectorIOException(e.getMessage(), e);
} catch (IllegalArgumentException e) {
throw new ConnectorException(e.getMessage(), e);
} // DO NOT catch IllegalStateException, let it pass
ObjectClassInfoBuilder objClassBuilder = createCommonObjectClassBuilder(getAccountObjectClassName(), dummyAccountObjectClass, supportsActivation);
// __PASSWORD__ attribute
AttributeInfo passwordAttrInfo;
switch (configuration.getPasswordReadabilityMode()) {
case DummyConfiguration.PASSWORD_READABILITY_MODE_READABLE:
case DummyConfiguration.PASSWORD_READABILITY_MODE_INCOMPLETE:
AttributeInfoBuilder aib = new AttributeInfoBuilder();
aib.setName(OperationalAttributes.PASSWORD_NAME);
aib.setType(GuardedString.class);
aib.setMultiValued(false);
aib.setReadable(true);
aib.setReturnedByDefault(false);
passwordAttrInfo = aib.build();
break;
default:
passwordAttrInfo = OperationalAttributeInfos.PASSWORD;
break;
}
objClassBuilder.addAttributeInfo(passwordAttrInfo);
return objClassBuilder.build();
}
private ObjectClassInfo createGroupObjectClass(boolean supportsActivation) {
// __GROUP__ objectclass
ObjectClassInfoBuilder objClassBuilder = createCommonObjectClassBuilder(getGroupObjectClassName(),
resource.getGroupObjectClass(), supportsActivation);
return objClassBuilder.build();
}
private ObjectClassInfo createPrivilegeObjectClass() {
ObjectClassInfoBuilder objClassBuilder = createCommonObjectClassBuilder(OBJECTCLASS_PRIVILEGE_NAME,
resource.getPrivilegeObjectClass(), false);
return objClassBuilder.build();
}
private ObjectClassInfo createOrgObjectClass() {
ObjectClassInfoBuilder objClassBuilder = createCommonObjectClassBuilder(OBJECTCLASS_ORG_NAME,
resource.getPrivilegeObjectClass(), false);
return objClassBuilder.build();
}
private List<ObjectClassInfo> createAuxiliaryObjectClasses() {
List<ObjectClassInfo> rv = new ArrayList<>();
for (Map.Entry<String, DummyObjectClass> entry : resource.getAuxiliaryObjectClassMap().entrySet()) {
ObjectClassInfoBuilder builder = createCommonObjectClassBuilder(entry.getKey(), entry.getValue(), false);
builder.setAuxiliary(true);
rv.add(builder.build());
}
return rv;
}
private void buildAttributes(ObjectClassInfoBuilder icfObjClassBuilder, DummyObjectClass dummyObjectClass) {
for (DummyAttributeDefinition dummyAttrDef : dummyObjectClass.getAttributeDefinitions()) {
AttributeInfoBuilder attrBuilder = new AttributeInfoBuilder(dummyAttrDef.getAttributeName(), dummyAttrDef.getAttributeType());
attrBuilder.setMultiValued(dummyAttrDef.isMulti());
attrBuilder.setRequired(dummyAttrDef.isRequired());
attrBuilder.setReturnedByDefault(dummyAttrDef.isReturnedByDefault());
icfObjClassBuilder.addAttributeInfo(attrBuilder.build());
}
}
/**
* {@inheritDoc}
*/
public Uid authenticate(final ObjectClass objectClass, final String userName, final GuardedString password, final OperationOptions options) {
log.info("authenticate::begin");
Uid uid = null;
log.info("authenticate::end");
return uid;
}
/**
* {@inheritDoc}
*/
public Uid resolveUsername(final ObjectClass objectClass, final String userName, final OperationOptions options) {
log.info("resolveUsername::begin");
Uid uid = null;
log.info("resolveUsername::end");
return uid;
}
/**
* {@inheritDoc}
*/
public Object runScriptOnConnector(ScriptContext request, OperationOptions options) {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
public Object runScriptOnResource(ScriptContext request, OperationOptions options) {
resource.runScript(request.getScriptLanguage(), request.getScriptText(), request.getScriptArguments());
return null;
}
/**
* {@inheritDoc}
*/
public FilterTranslator<Filter> createFilterTranslator(ObjectClass objectClass, OperationOptions options) {
log.info("createFilterTranslator::begin");
validate(objectClass);
log.info("createFilterTranslator::end");
return new DummyFilterTranslator() {
};
}
/**
* {@inheritDoc}
*/
public void executeQuery(ObjectClass objectClass, Filter query, ResultsHandler handler, OperationOptions options) {
log.info("executeQuery({0},{1},{2},{3})", objectClass, query, handler, options);
validate(objectClass);
validate(query);
notNull(handler, "Results handled object can't be null.");
Collection<String> attributesToGet = getAttrsToGet(options);
log.ok("attributesToGet={0}", attributesToGet);
if (configuration.getRequiredBaseContextOrgName() != null && shouldRequireBaseContext(objectClass, query, options)) {
if (options == null || options.getContainer() == null) {
throw new ConnectorException("No container option while base context is required");
}
QualifiedUid container = options.getContainer();
if (!configuration.getRequiredBaseContextOrgName().equals(container.getUid().getUidValue())) {
throw new ConnectorException("Base context of '"+configuration.getRequiredBaseContextOrgName()
+"' is required, but got '"+container.getUid().getUidValue()+"'");
}
}
try {
if (ObjectClass.ACCOUNT.is(objectClass.getObjectClassValue())) {
Collection<DummyAccount> accounts = resource.listAccounts();
for (DummyAccount account : accounts) {
ConnectorObject co = convertToConnectorObject(account, attributesToGet);
if (matches(query, co)) {
co = filterOutAttributesToGet(co, account, attributesToGet, options.getReturnDefaultAttributes());
handler.handle(co);
}
}
} else if (ObjectClass.GROUP.is(objectClass.getObjectClassValue())) {
Collection<DummyGroup> groups = resource.listGroups();
for (DummyGroup group : groups) {
ConnectorObject co = convertToConnectorObject(group, attributesToGet);
if (matches(query, co)) {
if (attributesToGetHasAttribute(attributesToGet, DummyGroup.ATTR_MEMBERS_NAME)) {
resource.recordGroupMembersReadCount();
}
co = filterOutAttributesToGet(co, group, attributesToGet, options.getReturnDefaultAttributes());
handler.handle(co);
}
}
} else if (objectClass.is(OBJECTCLASS_PRIVILEGE_NAME)) {
Collection<DummyPrivilege> privs = resource.listPrivileges();
for (DummyPrivilege priv : privs) {
ConnectorObject co = convertToConnectorObject(priv, attributesToGet);
if (matches(query, co)) {
co = filterOutAttributesToGet(co, priv, attributesToGet, options.getReturnDefaultAttributes());
handler.handle(co);
}
}
} else if (objectClass.is(OBJECTCLASS_ORG_NAME)) {
Collection<DummyOrg> orgs = resource.listOrgs();
for (DummyOrg org : orgs) {
ConnectorObject co = convertToConnectorObject(org, attributesToGet);
if (matches(query, co)) {
co = filterOutAttributesToGet(co, org, attributesToGet, options.getReturnDefaultAttributes());
handler.handle(co);
}
}
} else {
throw new ConnectorException("Unknown object class "+objectClass);
}
} catch (ConnectException e) {
log.info("executeQuery::exception "+e);
throw new ConnectionFailedException(e.getMessage(), e);
} catch (FileNotFoundException e) {
log.info("executeQuery::exception "+e);
throw new ConnectorIOException(e.getMessage(), e);
} catch (SchemaViolationException e) {
log.info("executeQuery::exception "+e);
throw new InvalidAttributeValueException(e.getMessage(), e);
} catch (ConflictException e) {
log.info("executeQuery::exception "+e);
throw new AlreadyExistsException(e);
}
log.info("executeQuery::end");
}
private boolean shouldRequireBaseContext(ObjectClass objectClass, Filter query,
OperationOptions options) {
if (objectClass.is(OBJECTCLASS_ORG_NAME)) {
return false;
}
if (!(query instanceof EqualsFilter)) {
return true;
}
if (((EqualsFilter)query).getAttribute().is(Uid.NAME)) {
return false;
}
return true;
}
private boolean matches(Filter query, ConnectorObject co) {
if (query == null) {
return true;
}
if (configuration.getCaseIgnoreValues() || configuration.getCaseIgnoreId()) {
return normalize(query).accept(normalize(co));
}
return query.accept(co);
}
private ConnectorObject normalize(ConnectorObject co) {
ConnectorObjectBuilder cob = new ConnectorObjectBuilder();
if (configuration.getCaseIgnoreId()) {
cob.setUid(co.getUid().getUidValue().toLowerCase());
cob.setName(co.getName().getName().toLowerCase());
} else {
cob.setUid(co.getUid());
cob.setName(co.getName());
}
cob.setObjectClass(co.getObjectClass());
for (Attribute attr : co.getAttributes()) {
cob.addAttribute(normalize(attr));
}
return cob.build();
}
private Filter normalize(Filter filter) {
if (filter instanceof ContainsFilter) {
AttributeFilter afilter = (AttributeFilter) filter;
return new ContainsFilter(normalize(afilter.getAttribute()));
} else if (filter instanceof EndsWithFilter) {
AttributeFilter afilter = (AttributeFilter) filter;
return new EndsWithFilter(normalize(afilter.getAttribute()));
} else if (filter instanceof EqualsFilter) {
AttributeFilter afilter = (AttributeFilter) filter;
return new EqualsFilter(normalize(afilter.getAttribute()));
} else if (filter instanceof GreaterThanFilter) {
AttributeFilter afilter = (AttributeFilter) filter;
return new GreaterThanFilter(normalize(afilter.getAttribute()));
} else if (filter instanceof GreaterThanOrEqualFilter) {
AttributeFilter afilter = (AttributeFilter) filter;
return new GreaterThanOrEqualFilter(normalize(afilter.getAttribute()));
} else if (filter instanceof LessThanFilter) {
AttributeFilter afilter = (AttributeFilter) filter;
return new LessThanFilter(normalize(afilter.getAttribute()));
} else if (filter instanceof LessThanOrEqualFilter) {
AttributeFilter afilter = (AttributeFilter) filter;
return new LessThanOrEqualFilter(normalize(afilter.getAttribute()));
} else if (filter instanceof StartsWithFilter) {
AttributeFilter afilter = (AttributeFilter) filter;
return new StartsWithFilter(normalize(afilter.getAttribute()));
} else if (filter instanceof ContainsAllValuesFilter) {
AttributeFilter afilter = (AttributeFilter) filter;
return new ContainsAllValuesFilter(normalize(afilter.getAttribute()));
} else if (filter instanceof NotFilter) {
NotFilter notFilter = (NotFilter) filter;
return new NotFilter(normalize(notFilter.getFilter()));
} else if (filter instanceof AndFilter) {
AndFilter andFilter = (AndFilter) filter;
return new AndFilter(normalize(andFilter.getLeft()), normalize(andFilter.getRight()));
} else if (filter instanceof OrFilter) {
OrFilter orFilter = (OrFilter) filter;
return new OrFilter(normalize(orFilter.getLeft()), normalize(orFilter.getRight()));
} else {
return filter;
}
}
private Attribute normalize(Attribute attr) {
if (configuration.getCaseIgnoreValues()) {
AttributeBuilder ab = new AttributeBuilder();
ab.setName(attr.getName());
for (Object value: attr.getValue()) {
if (value instanceof String) {
ab.addValue(((String)value).toLowerCase());
} else {
ab.addValue(value);
}
}
return ab.build();
} else {
return attr;
}
}
private ConnectorObject filterOutAttributesToGet(ConnectorObject co, DummyObject dummyObject,
Collection<String> attributesToGet, Boolean returnDefaultAttributes) {
if (attributesToGet == null) {
return co;
}
ConnectorObjectBuilder cob = new ConnectorObjectBuilder();
cob.setUid(co.getUid());
cob.setName(co.getName());
cob.setObjectClass(co.getObjectClass());
for (Attribute attr : co.getAttributes()) {
if (containsAttribute(attributesToGet, attr.getName()) ||
Boolean.TRUE.equals(returnDefaultAttributes) &&
(attr.getName().startsWith("__") || // brutal hack
dummyObject.isReturnedByDefault(attr.getName()))) {
cob.addAttribute(attr);
}
}
return cob.build();
}
private boolean containsAttribute(Collection<String> attrs, String attrName) {
for (String attr: attrs) {
if (StringUtils.equalsIgnoreCase(attr, attrName)) {
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
public void sync(ObjectClass objectClass, SyncToken token, SyncResultsHandler handler, final OperationOptions options) {
log.info("sync::begin");
validate(objectClass);
Collection<String> attributesToGet = getAttrsToGet(options);
try {
int syncToken = (Integer)token.getValue();
List<DummyDelta> deltas = resource.getDeltasSince(syncToken);
for (DummyDelta delta: deltas) {
Class<? extends DummyObject> deltaObjectClass = delta.getObjectClass();
if (objectClass.is(ObjectClass.ALL_NAME)) {
// take all changes
} else if (objectClass.is(ObjectClass.ACCOUNT_NAME)) {
if (deltaObjectClass != DummyAccount.class) {
log.ok("Skipping delta {0} because of objectclass mismatch", delta);
continue;
}
} else if (objectClass.is(ObjectClass.GROUP_NAME)) {
if (deltaObjectClass != DummyGroup.class) {
log.ok("Skipping delta {0} because of objectclass mismatch", delta);
continue;
}
}
SyncDeltaBuilder deltaBuilder = new SyncDeltaBuilder();
if (deltaObjectClass == DummyAccount.class) {
deltaBuilder.setObjectClass(ObjectClass.ACCOUNT);
} else if (deltaObjectClass == DummyGroup.class) {
deltaBuilder.setObjectClass(ObjectClass.GROUP);
} else if (deltaObjectClass == DummyPrivilege.class) {
deltaBuilder.setObjectClass(new ObjectClass(OBJECTCLASS_PRIVILEGE_NAME));
} else if (deltaObjectClass == DummyOrg.class) {
deltaBuilder.setObjectClass(new ObjectClass(OBJECTCLASS_ORG_NAME));
} else {
throw new IllegalArgumentException("Unknown delta objectClass "+deltaObjectClass);
}
SyncDeltaType deltaType;
if (delta.getType() == DummyDeltaType.ADD || delta.getType() == DummyDeltaType.MODIFY) {
if (resource.getSyncStyle() == DummySyncStyle.DUMB) {
deltaType = SyncDeltaType.CREATE_OR_UPDATE;
} else {
if (delta.getType() == DummyDeltaType.ADD) {
deltaType = SyncDeltaType.CREATE;
} else {
deltaType = SyncDeltaType.UPDATE;
}
}
if (deltaObjectClass == DummyAccount.class) {
DummyAccount account = resource.getAccountById(delta.getObjectId());
if (account == null) {
throw new IllegalStateException("We have delta for account '"+delta.getObjectId()+"' but such account does not exist");
}
ConnectorObject cobject = convertToConnectorObject(account, attributesToGet);
deltaBuilder.setObject(cobject);
} else if (deltaObjectClass == DummyGroup.class) {
DummyGroup group = resource.getGroupById(delta.getObjectId());
if (group == null) {
throw new IllegalStateException("We have delta for group '"+delta.getObjectId()+"' but such group does not exist");
}
ConnectorObject cobject = convertToConnectorObject(group, attributesToGet);
deltaBuilder.setObject(cobject);
} else if (deltaObjectClass == DummyPrivilege.class) {
DummyPrivilege privilege = resource.getPrivilegeById(delta.getObjectId());
if (privilege == null) {
throw new IllegalStateException("We have privilege for group '"+delta.getObjectId()+"' but such privilege does not exist");
}
ConnectorObject cobject = convertToConnectorObject(privilege, attributesToGet);
deltaBuilder.setObject(cobject);
} else {
throw new IllegalArgumentException("Unknown delta objectClass "+deltaObjectClass);
}
} else if (delta.getType() == DummyDeltaType.DELETE) {
deltaType = SyncDeltaType.DELETE;
} else {
throw new IllegalStateException("Unknown delta type "+delta.getType());
}
deltaBuilder.setDeltaType(deltaType);
deltaBuilder.setToken(new SyncToken(delta.getSyncToken()));
Uid uid;
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
uid = new Uid(delta.getObjectName());
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
if (nameHintChecksEnabled()) {
uid = new Uid(delta.getObjectId(), new Name(delta.getObjectName()));
} else {
uid = new Uid(delta.getObjectId());
}
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
deltaBuilder.setUid(uid);
SyncDelta syncDelta = deltaBuilder.build();
log.info("sync::handle {0}",syncDelta);
handler.handle(syncDelta);
}
} catch (ConnectException e) {
log.info("sync::exception "+e);
throw new ConnectionFailedException(e.getMessage(), e);
} catch (FileNotFoundException e) {
log.info("sync::exception "+e);
throw new ConnectorIOException(e.getMessage(), e);
} catch (SchemaViolationException e) {
log.info("sync::exception "+e);
throw new InvalidAttributeValueException(e.getMessage(), e);
} catch (ConflictException e) {
log.info("sync::exception "+e);
throw new AlreadyExistsException(e);
}
log.info("sync::end");
}
private Collection<String> getAttrsToGet(OperationOptions options) {
Collection<String> attributesToGet = null;
if (options != null) {
String[] attributesToGetArray = options.getAttributesToGet();
if (attributesToGetArray != null && attributesToGetArray.length != 0) {
attributesToGet = Arrays.asList(attributesToGetArray);
}
}
return attributesToGet;
}
/**
* {@inheritDoc}
*/
public SyncToken getLatestSyncToken(ObjectClass objectClass) {
log.info("getLatestSyncToken::begin");
validate(objectClass);
int latestSyncToken = resource.getLatestSyncToken();
log.info("getLatestSyncToken::end, returning token {0}.", latestSyncToken);
return new SyncToken(latestSyncToken);
}
/**
* {@inheritDoc}
*/
public void test() {
log.info("test::begin");
log.info("Validating configuration.");
configuration.validate();
// Produce log messages on all levels. The tests may check if they are really logged.
log.error(LOG_MARKER + " DummyConnectorIcfError");
log.info(LOG_MARKER + " DummyConnectorIcfInfo");
log.warn(LOG_MARKER + " DummyConnectorIcfWarn");
log.ok(LOG_MARKER + " DummyConnectorIcfOk");
log.info("Dummy Connector JUL logger as seen by the connector: " + julLogger + "; classloader " + julLogger.getClass().getClassLoader());
// Same thing using JUL
julLogger.severe(LOG_MARKER + " DummyConnectorJULsevere");
julLogger.warning(LOG_MARKER + " DummyConnectorJULwarning");
julLogger.info(LOG_MARKER + " DummyConnectorJULinfo");
julLogger.fine(LOG_MARKER + " DummyConnectorJULfine");
julLogger.finer(LOG_MARKER + " DummyConnectorJULfiner");
julLogger.finest(LOG_MARKER + " DummyConnectorJULfinest");
log.info("Test configuration was successful.");
log.info("test::end");
}
private ConnectorObjectBuilder createConnectorObjectBuilderCommon(DummyObject dummyObject,
DummyObjectClass objectClass, Collection<String> attributesToGet, boolean supportActivation) {
ConnectorObjectBuilder builder = new ConnectorObjectBuilder();
if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_NAME)) {
builder.setUid(dummyObject.getName());
} else if (configuration.getUidMode().equals(DummyConfiguration.UID_MODE_UUID)) {
builder.setUid(dummyObject.getId());
} else {
throw new IllegalStateException("Unknown UID mode "+configuration.getUidMode());
}
builder.addAttribute(Name.NAME, dummyObject.getName());
for (String name : dummyObject.getAttributeNames()) {
DummyAttributeDefinition attrDef = dummyObject.getAttributeDefinition(name);
if (attrDef == null) {
throw new IllegalArgumentException("Unknown account attribute '"+name+"'");
}
if (!attrDef.isReturnedByDefault()) {
if (attributesToGet != null && !attributesToGet.contains(name)) {
continue;
}
}
// Return all attributes that are returned by default. We will filter them out later.
Set<Object> values = dummyObject.getAttributeValues(name, Object.class);
if (configuration.isVaryLetterCase()) {
name = varyLetterCase(name);
}
if (values != null && !values.isEmpty()) {
builder.addAttribute(name, values);
}
}
if (supportActivation) {
if (attributesToGet == null || attributesToGet.contains(OperationalAttributes.ENABLE_NAME)) {
builder.addAttribute(OperationalAttributes.ENABLE_NAME, dummyObject.isEnabled());
}
if (dummyObject.getValidFrom() != null &&
(attributesToGet == null || attributesToGet.contains(OperationalAttributes.ENABLE_DATE_NAME))) {
builder.addAttribute(OperationalAttributes.ENABLE_DATE_NAME, convertToLong(dummyObject.getValidFrom()));
}
if (dummyObject.getValidTo() != null &&
(attributesToGet == null || attributesToGet.contains(OperationalAttributes.DISABLE_DATE_NAME))) {
builder.addAttribute(OperationalAttributes.DISABLE_DATE_NAME, convertToLong(dummyObject.getValidTo()));
}
}
if (configuration.isAddConnectorStateAttributes()) {
builder.addAttribute(DummyResource.ATTRIBUTE_CONNECTOR_TO_STRING, this.toString());
builder.addAttribute(DummyResource.ATTRIBUTE_CONNECTOR_STATIC_VAL, staticVal);
builder.addAttribute(DummyResource.ATTRIBUTE_CONNECTOR_CONFIGURATION_TO_STRING, configuration.toString());
}
if (!dummyObject.getAuxiliaryObjectClassNames().isEmpty()) {
builder.addAttribute(PredefinedAttributes.AUXILIARY_OBJECT_CLASS_NAME, dummyObject.getAuxiliaryObjectClassNames());
}
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;
}
return date.getTime();
}
private ConnectorObject convertToConnectorObject(DummyAccount account, Collection<String> attributesToGet) throws SchemaViolationException {
DummyObjectClass objectClass;
try {
objectClass = resource.getAccountObjectClass();
} catch (ConnectException e) {
log.error(e, e.getMessage());
throw new ConnectionFailedException(e.getMessage(), e);
} catch (FileNotFoundException e) {
log.error(e, e.getMessage());
throw new ConnectorIOException(e.getMessage(), e);
} catch (ConflictException e) {
log.error(e, e.getMessage());
throw new AlreadyExistsException(e);
}
ConnectorObjectBuilder builder = createConnectorObjectBuilderCommon(account, objectClass, attributesToGet, true);
builder.setObjectClass(ObjectClass.ACCOUNT);
// Password is not returned by default (hardcoded ICF specification)
if (account.getPassword() != null && attributesToGet != null && attributesToGet.contains(OperationalAttributes.PASSWORD_NAME)) {
switch (configuration.getPasswordReadabilityMode()) {
case DummyConfiguration.PASSWORD_READABILITY_MODE_READABLE:
GuardedString gs = new GuardedString(account.getPassword().toCharArray());
builder.addAttribute(OperationalAttributes.PASSWORD_NAME,gs);
break;
case DummyConfiguration.PASSWORD_READABILITY_MODE_INCOMPLETE:
AttributeBuilder ab = new AttributeBuilder();
ab.setName(OperationalAttributes.PASSWORD_NAME);
ab.setAttributeValueCompleteness(AttributeValueCompleteness.INCOMPLETE);
builder.addAttribute(ab.build());
break;
default:
// nothing to do
}
}
if (account.isLockout() != null) {
builder.addAttribute(OperationalAttributes.LOCK_OUT_NAME, account.isLockout());
}
return builder.build();
}
private ConnectorObject convertToConnectorObject(DummyGroup group, Collection<String> attributesToGet) {
ConnectorObjectBuilder builder = createConnectorObjectBuilderCommon(group, resource.getGroupObjectClass(),
attributesToGet, true);
builder.setObjectClass(ObjectClass.GROUP);
return builder.build();
}
private ConnectorObject convertToConnectorObject(DummyPrivilege priv, Collection<String> attributesToGet) {
ConnectorObjectBuilder builder = createConnectorObjectBuilderCommon(priv, resource.getPrivilegeObjectClass(),
attributesToGet, false);
builder.setObjectClass(new ObjectClass(OBJECTCLASS_PRIVILEGE_NAME));
return builder.build();
}
private ConnectorObject convertToConnectorObject(DummyOrg org, Collection<String> attributesToGet) {
ConnectorObjectBuilder builder = createConnectorObjectBuilderCommon(org, resource.getPrivilegeObjectClass(),
attributesToGet, false);
builder.setObjectClass(new ObjectClass(OBJECTCLASS_ORG_NAME));
return builder.build();
}
private DummyAccount convertToAccount(Set<Attribute> createAttributes) throws ConnectException, FileNotFoundException, SchemaViolationException, ConflictException {
log.ok("Create attributes: {0}", createAttributes);
String userName = Utils.getMandatoryStringAttribute(createAttributes, Name.NAME);
if (configuration.getUpCaseName()) {
userName = StringUtils.upperCase(userName);
}
log.ok("Username {0}", userName);
final DummyAccount newAccount = new DummyAccount(userName);
Boolean enabled = null;
for (Attribute attr : createAttributes) {
if (attr.is(Uid.NAME)) {
throw new IllegalArgumentException("UID explicitly specified in the account attributes");
} else if (attr.is(Name.NAME)) {
// Skip, already processed
} else if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
changePassword(newAccount,attr);
} else if (attr.is(OperationalAttributeInfos.ENABLE.getName())) {
enabled = getBoolean(attr);
newAccount.setEnabled(enabled);
} else if (attr.is(OperationalAttributeInfos.ENABLE_DATE.getName())) {
if (configuration.getSupportValidity()) {
newAccount.setValidFrom(getDate(attr));
} else {
throw new IllegalArgumentException("ENABLE_DATE specified in the account attributes while not supporting it");
}
} else if (attr.is(OperationalAttributeInfos.DISABLE_DATE.getName())) {
if (configuration.getSupportValidity()) {
newAccount.setValidTo(getDate(attr));
} else {
throw new IllegalArgumentException("DISABLE_DATE specified in the account attributes while not supporting it");
}
} else if (attr.is(OperationalAttributeInfos.LOCK_OUT.getName())) {
Boolean lockout = getBooleanNotNull(attr);
newAccount.setLockout(lockout);
} else {
String name = attr.getName();
try {
newAccount.replaceAttributeValues(name,attr.getValue());
} catch (SchemaViolationException e) {
// we cannot throw checked exceptions. But this one looks suitable.
// Note: let's do the bad thing and add exception loaded by this classloader as inner exception here
// The framework should deal with it ... somehow
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
if (configuration.getRequireExplicitEnable() && enabled == null) {
throw new IllegalArgumentException("Explicit value for ENABLE attribute was not provided and the connector is set to require it");
}
return newAccount;
}
private DummyGroup convertToGroup(Set<Attribute> createAttributes) throws ConnectException, FileNotFoundException, SchemaViolationException, ConflictException {
String icfName = Utils.getMandatoryStringAttribute(createAttributes,Name.NAME);
if (configuration.getUpCaseName()) {
icfName = StringUtils.upperCase(icfName);
}
final DummyGroup newGroup = new DummyGroup(icfName);
Boolean enabled = null;
for (Attribute attr : createAttributes) {
if (attr.is(Uid.NAME)) {
throw new IllegalArgumentException("UID explicitly specified in the group attributes");
} else if (attr.is(Name.NAME)) {
// Skip, already processed
} else if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
throw new IllegalArgumentException("Password specified for a group");
} else if (attr.is(OperationalAttributeInfos.ENABLE.getName())) {
enabled = getBooleanNotNull(attr);
newGroup.setEnabled(enabled);
} else if (attr.is(OperationalAttributeInfos.ENABLE_DATE.getName())) {
if (configuration.getSupportValidity()) {
newGroup.setValidFrom(getDate(attr));
} else {
throw new IllegalArgumentException("ENABLE_DATE specified in the group attributes while not supporting it");
}
} else if (attr.is(OperationalAttributeInfos.DISABLE_DATE.getName())) {
if (configuration.getSupportValidity()) {
newGroup.setValidTo(getDate(attr));
} else {
throw new IllegalArgumentException("DISABLE_DATE specified in the group attributes while not supporting it");
}
} else {
String name = attr.getName();
try {
newGroup.replaceAttributeValues(name,attr.getValue());
} catch (SchemaViolationException e) {
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
return newGroup;
}
private DummyPrivilege convertToPriv(Set<Attribute> createAttributes) throws ConnectException, FileNotFoundException, ConflictException {
String icfName = Utils.getMandatoryStringAttribute(createAttributes,Name.NAME);
if (configuration.getUpCaseName()) {
icfName = StringUtils.upperCase(icfName);
}
final DummyPrivilege newPriv = new DummyPrivilege(icfName);
for (Attribute attr : createAttributes) {
if (attr.is(Uid.NAME)) {
throw new IllegalArgumentException("UID explicitly specified in the group attributes");
} else if (attr.is(Name.NAME)) {
// Skip, already processed
} else if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
throw new IllegalArgumentException("Password specified for a privilege");
} else if (attr.is(OperationalAttributeInfos.ENABLE.getName())) {
throw new IllegalArgumentException("Unsupported ENABLE attribute in privilege");
} else {
String name = attr.getName();
try {
newPriv.replaceAttributeValues(name,attr.getValue());
} catch (SchemaViolationException e) {
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
return newPriv;
}
private DummyOrg convertToOrg(Set<Attribute> createAttributes) throws ConnectException, FileNotFoundException, ConflictException {
String icfName = Utils.getMandatoryStringAttribute(createAttributes,Name.NAME);
if (configuration.getUpCaseName()) {
icfName = StringUtils.upperCase(icfName);
}
final DummyOrg newOrg = new DummyOrg(icfName);
for (Attribute attr : createAttributes) {
if (attr.is(Uid.NAME)) {
throw new IllegalArgumentException("UID explicitly specified in the org attributes");
} else if (attr.is(Name.NAME)) {
// Skip, already processed
} else if (attr.is(OperationalAttributeInfos.PASSWORD.getName())) {
throw new IllegalArgumentException("Password specified for a org");
} else if (attr.is(OperationalAttributeInfos.ENABLE.getName())) {
throw new IllegalArgumentException("Unsupported ENABLE attribute in org");
} else {
String name = attr.getName();
try {
newOrg.replaceAttributeValues(name,attr.getValue());
} catch (SchemaViolationException e) {
throw new IllegalArgumentException(e.getMessage(),e);
}
}
}
return newOrg;
}
private Boolean getBoolean(Attribute attr) {
if (attr.getValue() == null || attr.getValue().isEmpty()) {
return null;
}
Object object = attr.getValue().get(0);
if (!(object instanceof Boolean)) {
throw new IllegalArgumentException("Attribute "+attr.getName()+" was provided as "+object.getClass().getName()+" while expecting boolean");
}
return ((Boolean)object).booleanValue();
}
private boolean getBooleanNotNull(Attribute attr) {
if (attr.getValue() == null || attr.getValue().isEmpty()) {
throw new IllegalArgumentException("Empty "+attr.getName()+" attribute was provided");
}
Object object = attr.getValue().get(0);
if (!(object instanceof Boolean)) {
throw new IllegalArgumentException("Attribute "+attr.getName()+" was provided as "+object.getClass().getName()+" while expecting boolean");
}
return ((Boolean)object).booleanValue();
}
private Date getDate(Attribute attr) {
if (attr.getValue() == null || attr.getValue().isEmpty()) {
throw new IllegalArgumentException("Empty date attribute was provided");
}
Object object = attr.getValue().get(0);
if (object == null){
return null;
}
if (!(object instanceof Long)) {
throw new IllegalArgumentException("Date attribute was provided as "+object.getClass().getName()+" while expecting long");
}
return new Date(((Long)object).longValue());
}
private void changePassword(final DummyAccount account, Attribute attr) throws ConnectException, FileNotFoundException, SchemaViolationException, ConflictException {
final String[] passwdArray = { null };
if (attr.getValue() != null && !attr.getValue().isEmpty()) {
Object passwdObject = attr.getValue().get(0);
if (!(passwdObject instanceof GuardedString)) {
throw new IllegalArgumentException(
"Password was provided as " + passwdObject.getClass().getName() + " while expecting GuardedString");
}
((GuardedString)passwdObject).access(new Accessor() {
@Override
public void access(char[] passwdChars) {
if (configuration.getMinPasswordLength() != null && passwdChars.length < configuration.getMinPasswordLength()) {
throw new InvalidAttributeValueException("Password too short");
}
passwdArray[0] = new String(passwdChars);
}
});
} else {
// empty password => null
}
account.setPassword(passwdArray[0]);
}
private boolean attributesToGetHasAttribute(Collection<String> attributesToGet, String attrName) {
if (attributesToGet == null) {
return true;
}
return attributesToGet.contains(attrName);
}
public void validate(ObjectClass oc) {
if (oc == null) {
throw new IllegalArgumentException("Object class must not be null.");
}
}
public void validate(Uid uid) {
if (uid == null) {
throw new IllegalArgumentException("Uid must not be null.");
}
if (nameHintChecksEnabled()) {
if (uid.getNameHint() == null) {
throw new InvalidAttributeValueException("Uid name hint must not be null.");
}
if (StringUtils.isBlank(uid.getNameHintValue())) {
throw new InvalidAttributeValueException("Uid name hint must not be empty.");
}
}
}
private void validate(Filter filter) {
if (filter == null) {
return;
}
if (nameHintChecksEnabled()) {
filter.accept(new FilterVisitor<String,String>() {
@Override
public String visitAndFilter(String p, AndFilter filter) {
return null;
}
@Override
public String visitContainsFilter(String p, ContainsFilter filter) {
return null;
}
@Override
public String visitContainsAllValuesFilter(String p, ContainsAllValuesFilter filter) {
return null;
}
@Override
public String visitEqualsFilter(String p, EqualsFilter filter) {
if (filter.getAttribute().is(Uid.NAME)) {
Uid uid = (Uid)filter.getAttribute();
if (uid.getNameHint() == null) {
throw new InvalidAttributeValueException("Uid name hint must not be null in filter "+filter);
}
if (StringUtils.isBlank(uid.getNameHintValue())) {
throw new InvalidAttributeValueException("Uid name hint must not be empty in filter "+filter);
}
}
return null;
}
@Override
public String visitExtendedFilter(String p, Filter filter) {
return null;
}
@Override
public String visitGreaterThanFilter(String p, GreaterThanFilter filter) {
return null;
}
@Override
public String visitGreaterThanOrEqualFilter(String p, GreaterThanOrEqualFilter filter) {
return null;
}
@Override
public String visitLessThanFilter(String p, LessThanFilter filter) {
return null;
}
@Override
public String visitLessThanOrEqualFilter(String p, LessThanOrEqualFilter filter) {
return null;
}
@Override
public String visitNotFilter(String p, NotFilter filter) {
return null;
}
@Override
public String visitOrFilter(String p, OrFilter filter) {
return null;
}
@Override
public String visitStartsWithFilter(String p, StartsWithFilter filter) {
return null;
}
@Override
public String visitEndsWithFilter(String p, EndsWithFilter filter) {
return null;
}
}, null);
}
}
private boolean nameHintChecksEnabled() {
return configuration.isRequireNameHint() && !resource.isDisableNameHintChecks();
}
}