/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2011-2013 ForgeRock AS. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* http://forgerock.org/license/CDDLv1.0.html
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at http://forgerock.org/license/CDDLv1.0.html
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*/
package org.forgerock.openidm.provisioner.openicf.connector;
import org.identityconnectors.common.script.Script;
import org.identityconnectors.common.script.ScriptExecutor;
import org.identityconnectors.common.script.ScriptExecutorFactory;
import org.identityconnectors.common.security.GuardedByteArray;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.identityconnectors.framework.common.objects.*;
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.ConnectorClass;
import org.identityconnectors.framework.spi.PoolableConnector;
import org.identityconnectors.framework.spi.operations.*;
import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.util.EnumSet;
import java.util.Set;
/**
* Sample Class Doc
*
* @version $Revision$ $Date$
*/
@ConnectorClass(displayNameKey = "TEST", configurationClass = TestConfiguration.class)
public class TestConnector implements PoolableConnector, AuthenticateOp, CreateOp, DeleteOp, ResolveUsernameOp,
SchemaOp, ScriptOnConnectorOp, ScriptOnResourceOp, SearchOp<String>, SyncOp, TestOp, UpdateAttributeValuesOp, UpdateOp, AttributeNormalizer {
@Override
public Attribute normalizeAttribute(ObjectClass oclass, Attribute attribute) {
return null;
}
/**
* Simple authentication with two parameters presumed to be user name and
* password. The {@link org.identityconnectors.framework.spi.Connector} developer is expected to attempt to
* authenticate these credentials natively. If the authentication fails the
* developer should throw a type of {@link RuntimeException} either
* {@link IllegalArgumentException} or if a native exception is available
* and if its of type {@link RuntimeException} simple throw it. If the
* native exception is not a {@link RuntimeException} wrap it in one and
* throw it. This will provide the most detail for logging problem and
* failed attempts.
* <p/>
* The developer is of course encourage to try and throw the most
* informative exception as possible. In that regards there are several
* exceptions provided in the exceptions package. For newBuilder one of the
* most common is {@link org.identityconnectors.framework.common.exceptions.InvalidPasswordException}.
*
* @param objectClass The object class to use for authenticate.
* Will typically be an account. Must not be null.
* @param username the name based credential for authentication.
* @param password the password based credential for authentication.
* @param options additional options that impact the way this operation is run.
* If the caller passes null, the framework will convert this into
* an empty set of options, so SPI need not worry
* about this ever being null.
* @return Uid The uid of the account that was used to authenticate
* @throws RuntimeException iff native authentication fails. If a native exception if
* available attempt to throw it.
*/
@Override
public Uid authenticate(ObjectClass objectClass, String username, GuardedString password, OperationOptions options) {
return null;
}
/**
* Checks if the connector is still alive.
* <p/>
* <p>A connector can spend a large amount of time in the pool before
* being used. This method is intended to check if the connector is
* alive and operations can be invoked on it (for newBuilder, an implementation
* would check that the connector's physical connection to the resource
* has not timed out).</p>
* <p/>
* <p>The major difference between this method and {@link org.identityconnectors.framework.spi.operations.TestOp#test()} is that
* this method must do only the minimum that is necessary to check that the
* connector is still alive. <code>TestOp.test()</code> does a more thorough
* check of the environment specified in the Configuration, and can therefore
* be much slower.</p>
* <p/>
* <p>This method can be called often. Implementations should do their
* best to keep this method fast.</p>
*
* @throws RuntimeException if the connector is no longer alive.
*/
@Override
public void checkAlive() {
}
/**
* Return the configuration that was passed to {@link #init(org.identityconnectors.framework.spi.Configuration)}.
*
* @return The configuration that was passed to {@link #init(org.identityconnectors.framework.spi.Configuration)}.
*/
@Override
public Configuration getConfiguration() {
return null;
}
/**
* Initialize the connector with its configuration. For newBuilder in a JDBC
* {@link org.identityconnectors.framework.spi.Connector} this would include the database URL, password, and
* user.
*
* @param cfg newBuilder of the {@link org.identityconnectors.framework.spi.Configuration} object implemented by
* the {@link org.identityconnectors.framework.spi.Connector} developer and populated with information
* in order to initialize the {@link org.identityconnectors.framework.spi.Connector}.
*/
@Override
public void init(Configuration cfg) {
}
/**
* Dispose of any resources the {@link org.identityconnectors.framework.spi.Connector} uses.
*/
@Override
public void dispose() {
}
/**
* The {@link org.identityconnectors.framework.spi.Connector} developer is responsible for taking the attributes
* given (which always includes the {@link org.identityconnectors.framework.common.objects.ObjectClass}) and create an
* object and its {@link org.identityconnectors.framework.common.objects.Uid}. The {@link org.identityconnectors.framework.spi.Connector} developer must return
* the {@link org.identityconnectors.framework.common.objects.Uid} so that the caller can refer to the created object.
* <p/>
* *Note: There will never be a {@link org.identityconnectors.framework.common.objects.Uid} passed in with the attribute set for this method.
* If the resource supports some sort of mutable {@link org.identityconnectors.framework.common.objects.Uid}, you should create your
* own resource-specific attribute for it, such as <I>unix_uid</I>.
*
* @param attrs includes all the attributes necessary to create the resource
* object including the {@link org.identityconnectors.framework.common.objects.ObjectClass} attribute and
* {@link org.identityconnectors.framework.common.objects.Name} attribute.
* @param options additional options that impact the way this operation is run.
* If the caller passes null, the framework will convert this into
* an empty set of options, so SPI need not worry
* about this ever being null.
* @return the unique id for the object that is created. For newBuilder in
* LDAP this would be the 'dn', for a database this would be the
* primary key, and for 'ActiveDirectory' this would be the GUID.
*/
@Override
public Uid create(ObjectClass oclass, Set<Attribute> attrs, OperationOptions options) {
return null;
}
/**
* The {@link org.identityconnectors.framework.spi.Connector} developer is responsible for calling the native
* delete methods to remove the object specified by its unique id.
*
* @param objClass type of object to delete.
* @param uid The unique id that specifies the object to delete.
* @param options additional options that impact the way this operation is run.
* If the caller passes null, the framework will convert this into
* an empty set of options, so SPI need not worry
* about this ever being null.
* @throws org.identityconnectors.framework.common.exceptions.UnknownUidException
* iff the {@link org.identityconnectors.framework.common.objects.Uid} does not exist on the resource.
*/
@Override
public void delete(ObjectClass objClass, Uid uid, OperationOptions options) {
}
/**
* Resolve an object to its {@link org.identityconnectors.framework.common.objects.Uid} based on its username.
* This is a companion to the simple {@link org.identityconnectors.framework.spi.operations.AuthenticateOp authentication}.
* The difference is that this method does not have a password parameter and
* does not try to authenticate the credentials; instead, it
* returns the {@link org.identityconnectors.framework.common.objects.Uid} corresponding to the username.
* Implementations method must, however, validate the username (i.e., they must throw
* and exception if the username does not correspond to an existing object).
* <p/>
* If the username validation fails, the
* developer should throw a type of {@link RuntimeException} either
* {@link IllegalArgumentException} or if a native exception is available
* and if its of type {@link RuntimeException} simple throw it. If the
* native exception is not a {@link RuntimeException} wrap it in one and
* throw it. This will provide the most detail for logging problem and
* failed attempts.
* <p/>
* The developer is of course encourage to try and throw the most
* informative exception as possible. In that regards there are several
* exceptions provided in the exceptions package. For newBuilder one of the
* most common is {@link org.identityconnectors.framework.common.exceptions.UnknownUidException}.
*
* @param objectClass The object class to resolve the username for.
* Will typically be an account. Will not be null.
* @param username the username to resolve. Will not be null.
* @param options additional options that impact the way this operation is run.
* If the caller passes null, the framework will convert this into
* an empty set of options, so SPI need not worry
* about this ever being null.
* @return Uid The uid of the object corresponding to the username.
* @throws RuntimeException iff the username cannot be resolved. If a native exception is
* available attempt to throw it.
* @since 1.1
*/
@Override
public Uid resolveUsername(ObjectClass objectClass, String username, OperationOptions options) {
return null;
}
/**
* Describes the types of objects this {@link org.identityconnectors.framework.spi.Connector} supports. This
* method is considered an operation since determining supported objects may
* require configuration information and allows this determination to be
* dynamic.
* <p/>
* The special {@link org.identityconnectors.framework.common.objects.Uid} attribute
* should never appear in the schema, as it is not a true attribute of an object,
* rather a reference to it. If your resource object-class has a writable unique id attribute
* that is different than its {@link org.identityconnectors.framework.common.objects.Name},
* then your schema should contain a resource-specific attribute that represents this unique id.
* For example, a Unix account object might contain <I>unix_uid</I>.
*
* @return basic schema supported by this {@link org.identityconnectors.framework.spi.Connector}.
*/
@Override
public Schema schema() {
SchemaBuilder schemaBuilder = new SchemaBuilder(TestConnector.class);
schemaBuilder.defineOperationOption("_OperationOption-boolean", boolean.class);
schemaBuilder.defineOperationOption("_OperationOption-Boolean", Boolean.class);
schemaBuilder.defineOperationOption("_OperationOption-char", char.class);
schemaBuilder.defineOperationOption("_OperationOption-Character", Character.class);
schemaBuilder.defineOperationOption("_OperationOption-double", double.class);
schemaBuilder.defineOperationOption("_OperationOption-Double", Double.class);
schemaBuilder.defineOperationOption("_OperationOption-File", File.class);
schemaBuilder.defineOperationOption("_OperationOption-FileArray", File[].class);
schemaBuilder.defineOperationOption("_OperationOption-float", float.class);
schemaBuilder.defineOperationOption("_OperationOption-Float", Float.class);
schemaBuilder.defineOperationOption("_OperationOption-GuardedByteArray", GuardedByteArray.class);
schemaBuilder.defineOperationOption("_OperationOption-GuardedString", GuardedString.class);
schemaBuilder.defineOperationOption("_OperationOption-int", int.class);
schemaBuilder.defineOperationOption("_OperationOption-Integer", Integer.class);
schemaBuilder.defineOperationOption("_OperationOption-long", long.class);
schemaBuilder.defineOperationOption("_OperationOption-Long", Long.class);
schemaBuilder.defineOperationOption("_OperationOption-ObjectClass", ObjectClass.class);
schemaBuilder.defineOperationOption("_OperationOption-QualifiedUid", QualifiedUid.class);
schemaBuilder.defineOperationOption("_OperationOption-Script", Script.class);
schemaBuilder.defineOperationOption("_OperationOption-String", String.class);
schemaBuilder.defineOperationOption("_OperationOption-StringArray", String[].class);
schemaBuilder.defineOperationOption("_OperationOption-Uid ", Uid.class);
schemaBuilder.defineOperationOption("_OperationOption-URI", URI.class);
ObjectClassInfoBuilder ocBuilder = new ObjectClassInfoBuilder();
// Users
ocBuilder = new ObjectClassInfoBuilder();
ocBuilder.setType(ObjectClass.ACCOUNT_NAME);
//The name of the object
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build(Name.NAME, String.class, EnumSet.of(AttributeInfo.Flags.REQUIRED, AttributeInfo.Flags.NOT_UPDATEABLE)));
//All Predefined Attribute Info
ocBuilder.addAttributeInfo(PredefinedAttributeInfos.DESCRIPTION);
ocBuilder.addAttributeInfo(PredefinedAttributeInfos.GROUPS);
ocBuilder.addAttributeInfo(PredefinedAttributeInfos.LAST_LOGIN_DATE);
ocBuilder.addAttributeInfo(PredefinedAttributeInfos.LAST_PASSWORD_CHANGE_DATE);
ocBuilder.addAttributeInfo(PredefinedAttributeInfos.PASSWORD_CHANGE_INTERVAL);
ocBuilder.addAttributeInfo(PredefinedAttributeInfos.SHORT_NAME);
//All Operational Attribute Info
ocBuilder.addAttributeInfo(OperationalAttributeInfos.CURRENT_PASSWORD);
ocBuilder.addAttributeInfo(OperationalAttributeInfos.DISABLE_DATE);
ocBuilder.addAttributeInfo(OperationalAttributeInfos.ENABLE);
ocBuilder.addAttributeInfo(OperationalAttributeInfos.ENABLE_DATE);
ocBuilder.addAttributeInfo(OperationalAttributeInfos.LOCK_OUT);
ocBuilder.addAttributeInfo(OperationalAttributeInfos.PASSWORD);
ocBuilder.addAttributeInfo(OperationalAttributeInfos.PASSWORD_EXPIRATION_DATE);
ocBuilder.addAttributeInfo(OperationalAttributeInfos.PASSWORD_EXPIRED);
//All possible attribute types and flags
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-BigDecimal", BigDecimal.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-BigInteger", BigInteger.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-boolean", boolean.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-Boolean", Boolean.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-byte[]", byte[].class, EnumSet.of(AttributeInfo.Flags.NOT_RETURNED_BY_DEFAULT, AttributeInfo.Flags.NOT_UPDATEABLE)));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-char", char.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-Character", Character.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-double", double.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-Double", Double.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-float", float.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-Float", Float.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-GuardedByteArray", GuardedByteArray.class, EnumSet.of(AttributeInfo.Flags.REQUIRED, AttributeInfo.Flags.NOT_UPDATEABLE)));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-GuardedString", GuardedString.class, EnumSet.of(AttributeInfo.Flags.REQUIRED, AttributeInfo.Flags.NOT_UPDATEABLE)));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-int", int.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-Integer", Integer.class));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-long", long.class, EnumSet.of(AttributeInfo.Flags.NOT_RETURNED_BY_DEFAULT, AttributeInfo.Flags.NOT_READABLE, AttributeInfo.Flags.NOT_UPDATEABLE)));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-Long", Long.class, EnumSet.of(AttributeInfo.Flags.NOT_CREATABLE, AttributeInfo.Flags.NOT_UPDATEABLE)));
ocBuilder.addAttributeInfo(AttributeInfoBuilder.build("_Attribute-String", String.class, EnumSet.of(AttributeInfo.Flags.MULTIVALUED, AttributeInfo.Flags.NOT_UPDATEABLE)));
schemaBuilder.defineObjectClass(ocBuilder.build());
return schemaBuilder.build();
}
/**
* Runs the script request.
*
* @param request The script and arguments to run.
* @param options Additional options that control how the script is
* run.
* @return The result of the script. The return type must be
* a type that the framework supports for serialization.
* See {@link org.identityconnectors.framework.common.serializer.ObjectSerializerFactory} for a list of supported types.
*/
@Override
public Object runScriptOnConnector(ScriptContext request, OperationOptions options) {
if ("SHELL".equals(request.getScriptLanguage())) {
throw new ConnectorException("SHELL Script is not supported");
} else if ("Groovy".equals(request.getScriptLanguage())) {
return executeGroovyScript(request);
}
return null;
}
/**
* Run the specified script <i>on the target resource</i>
* that this connector manages.
*
* @param request The script and arguments to run.
* @param options Additional options that control
* how the script is run.
* @return The result of the script. The return type must be
* a type that the framework supports for serialization.
* See {@link org.identityconnectors.framework.common.serializer.ObjectSerializerFactory} for a list of supported types.
*/
@Override
public Object runScriptOnResource(ScriptContext request, OperationOptions options) {
if ("SHELL".equals(request.getScriptLanguage())) {
return "OK";
} else if ("Groovy".equals(request.getScriptLanguage())) {
return executeGroovyScript(request);
}
throw new ConnectorException(request.getScriptLanguage() + " script language is not supported");
}
private Object executeGroovyScript(ScriptContext request) {
Object result = null;
try {
ScriptExecutorFactory factory = ScriptExecutorFactory.newInstance(request.getScriptLanguage());
ScriptExecutor runOnConnectorExecutor = factory.newScriptExecutor(getClass().getClassLoader(), request.getScriptText(), true);
result = runOnConnectorExecutor.execute(request.getScriptArguments());
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
/**
* Creates a filter translator that will translate a specified
* {@link org.identityconnectors.framework.common.objects.filter.Filter filter}
* into one or more native queries.
* Each of these native queries will be passed subsequently into
* <code>executeQuery()</code>.
*
* @param oclass The object class for the search. Will never be null.
* @param options additional options that impact the way this operation is run.
* If the caller passes null, the framework will convert this
* into an empty set of options, so SPI need not worry about this
* ever being null.
* @return A filter translator. This must not be <code>null</code>.
* A <code>null</code> return value will cause the API
* (<code>SearchApiOp</code>) to throw {@link NullPointerException}.
*/
@Override
public FilterTranslator<String> createFilterTranslator(ObjectClass oclass, OperationOptions options) {
return null;
}
/**
* ConnectorFacade calls this method once for each native query
* that the {@linkplain #createFilterTranslator(org.identityconnectors.framework.common.objects.ObjectClass, org.identityconnectors.framework.common.objects.OperationOptions) FilterTranslator}
* produces in response to the <code>Filter</code> passed into
* {@link org.identityconnectors.framework.api.operations.SearchApiOp#search(org.identityconnectors.framework.common.objects.ObjectClass, org.identityconnectors.framework.common.objects.filter.Filter, org.identityconnectors.framework.common.objects.ResultsHandler, org.identityconnectors.framework.common.objects.OperationOptions)} SearchApiOp}.
* If the <code>FilterTranslator</code> produces more than one native query, then ConnectorFacade
* will automatically merge the results from each query and eliminate any duplicates.
* NOTE that this implies an in-memory data structure that holds a set of
* Uid values, so memory usage in the event of multiple queries will be O(N)
* where N is the number of results. This is why it is important that
* the FilterTranslator for each Connector implement OR if possible.
*
* @param oclass The object class for the search. Will never be null.
* @param query The native query to run. A value of null means
* "return every newBuilder of the given object class".
* @param handler Results should be returned to this handler
* @param options Additional options that impact the way this operation is run.
* If the caller passes null, the framework will convert this into
* an empty set of options, so SPI need not guard against options being null.
*/
@Override
public void executeQuery(ObjectClass oclass, String query, ResultsHandler handler, OperationOptions options) {
ConnectorObjectBuilder bld = new ConnectorObjectBuilder();
bld.setName("BEEBLEBROX");
bld.setUid("beeblebrox");
bld.addAttribute("location", "Betelgeuse");
bld.addAttribute("invention", "Pan Galactic Gargle Blaster");
handler.handle(bld.build());
}
/**
* Request synchronization events--i.e., native changes to target objects.
* <p/>
* This method will call the specified {@linkplain
* org.identityconnectors.framework.common.objects.SyncResultsHandler#
* handle(org.identityconnectors.framework.common.objects.SyncDelta)} handler}
* once to pass back each matching
* {@linkplain org.identityconnectors.framework.common.objects.SyncDelta synchronization event}.
* Once this method returns, this method will no longer invoke the specified handler.
* <p/>
* Each {@linkplain org.identityconnectors.framework.common.objects.SyncDelta#getToken()
* synchronization event contains a token}
* that can be used to resume reading events <i>starting from that point in the event stream</i>.
* In typical usage, a client will save the token from the final synchronization event
* that was received from one invocation of this {@code sync()} method
* and then pass that token into that client's buildNext call to this {@code sync()} method.
* This allows a client to "pick up where he left off" in receiving synchronization events.
* However, a client can pass the token from <i>any</i> synchronization event
* into a subsequent invocation of this {@code sync()} method.
* This will return synchronization events (that represent native changes that
* occurred) immediately subsequent to the event from which the client obtained the token.
* <p/>
* A client that wants to read synchronization events "starting now"
* can call {@link #getLatestSyncToken(org.identityconnectors.framework.common.objects.ObjectClass)}
* and then pass that token
* into this {@code sync()} method.
*
* @param objClass The class of object for which to return synchronization events. Must not be null.
* @param token The token representing the last token from the previous sync.
* The {@code SyncResultsHandler} will return any number of
* {@linkplain org.identityconnectors.framework.common.objects.SyncDelta} objects,
* each of which contains a token.
* Should be {@code null} if this is the client's first call
* to the {@code sync()} method for this connector.
* @param handler The result handler. Must not be null.
* @param options Options that affect the way this operation is run.
* If the caller passes {@code null},
* the framework will convert this into an empty set of options,
* so an implementation need not guard against this being null.
* @throws IllegalArgumentException if {@code objClass} or {@code handler} is null
* or if any argument is invalid.
*/
@Override
public void sync(ObjectClass objClass, SyncToken token, SyncResultsHandler handler, OperationOptions options) {
}
/**
* Returns the token corresponding to the most recent synchronization event.
* <p/>
* An application that wants to receive synchronization events "starting now"
* --i.e., wants to receive only native changes that occur after this method is called--
* should call this method and then pass the resulting token
* into {@linkplain #sync(org.identityconnectors.framework.common.objects.ObjectClass,
* org.identityconnectors.framework.common.objects.SyncToken,
* org.identityconnectors.framework.common.objects.SyncResultsHandler,
* org.identityconnectors.framework.common.objects.OperationOptions)} the sync() method}.
*
* @param objClass the class of object for which to find the most recent
* synchronization event (if any). Must not be null.
* @return A token if synchronization events exist; otherwise {@code null}.
* @throws IllegalArgumentException if {@code objClass} is null or is invalid.
*/
@Override
public SyncToken getLatestSyncToken(ObjectClass objClass) {
return null;
}
/**
* Tests the {@link org.identityconnectors.framework.spi.Configuration} with the connector.
*
* @throws RuntimeException iff the configuration is not valid or the test failed. Implementations
* are encouraged to throw the most specific exception available.
* When no specific exception is available, implementations can throw
* {@link org.identityconnectors.framework.common.exceptions.ConnectorException}.
*/
@Override
public void test() {
}
/**
* Update the object specified by the {@link org.identityconnectors.framework.common.objects.ObjectClass} and
* {@link org.identityconnectors.framework.common.objects.Uid},
* adding to the current values of each attribute the values provided.
* <p/>
* For each attribute that the input set contains, add to
* the current values of that attribute in the target object all of the
* values of that attribute in the input set.
* <p/>
* NOTE that this does not specify how to handle duplicate values.
* The general assumption for an attribute of a {@code ConnectorObject}
* is that the values for an attribute may contain duplicates.
* Therefore, in general simply <em>append</em> the provided values
* to the current value for each attribute.
* <p/>
*
* @param objclass the type of object to modify. Will never be null.
* @param uid the uid of the object to modify. Will never be null.
* @param valuesToAdd set of {@link org.identityconnectors.framework.common.objects.Attribute} deltas. The values for the attributes
* in this set represent the values to add to attributes in the object.
* merged. This set will never include {@link org.identityconnectors.framework.common.objects.OperationalAttributes operational attributes}.
* Will never be null.
* @param options additional options that impact the way this operation is run.
* Will never be null.
* @return the {@link org.identityconnectors.framework.common.objects.Uid} of the updated object in case the update changes
* the formation of the unique identifier.
* @throws org.identityconnectors.framework.common.exceptions.UnknownUidException
* iff the {@link org.identityconnectors.framework.common.objects.Uid} does not exist on the resource.
*/
@Override
public Uid addAttributeValues(ObjectClass objclass, Uid uid, Set<Attribute> valuesToAdd, OperationOptions options) {
return null;
}
/**
* Update the object specified by the {@link org.identityconnectors.framework.common.objects.ObjectClass} and {@link org.identityconnectors.framework.common.objects.Uid},
* removing from the current values of each attribute the values provided.
* <p/>
* For each attribute that the input set contains,
* remove from the current values of that attribute in the target object
* any value that matches one of the values of the attribute from the input set.
* <p/>
* NOTE that this does not specify how to handle unmatched values.
* The general assumption for an attribute of a {@code ConnectorObject}
* is that the values for an attribute are merely <i>representational state</i>.
* Therefore, the implementer should simply ignore any provided value
* that does not match a current value of that attribute in the target
* object. Deleting an unmatched value should always succeed.
*
* @param objclass the type of object to modify. Will never be null.
* @param uid the uid of the object to modify. Will never be null.
* @param valuesToRemove set of {@link org.identityconnectors.framework.common.objects.Attribute} deltas. The values for the attributes
* in this set represent the values to remove from attributes in the object.
* merged. This set will never include {@link org.identityconnectors.framework.common.objects.OperationalAttributes operational attributes}.
* Will never be null.
* @param options additional options that impact the way this operation is run.
* Will never be null..
* @return the {@link org.identityconnectors.framework.common.objects.Uid} of the updated object in case the update changes
* the formation of the unique identifier.
* @throws org.identityconnectors.framework.common.exceptions.UnknownUidException
* iff the {@link org.identityconnectors.framework.common.objects.Uid} does not exist on the resource.
*/
@Override
public Uid removeAttributeValues(ObjectClass objclass, Uid uid, Set<Attribute> valuesToRemove, OperationOptions options) {
return null;
}
/**
* Update the object specified by the {@link org.identityconnectors.framework.common.objects.ObjectClass} and {@link org.identityconnectors.framework.common.objects.Uid},
* replacing the current values of each attribute with the values
* provided.
* <p/>
* For each input attribute, replace
* all of the current values of that attribute in the target object with
* the values of that attribute.
* <p/>
* If the target object does not currently contain an attribute that the
* input set contains, then add this
* attribute (along with the provided values) to the target object.
* <p/>
* If the value of an attribute in the input set is
* {@code null}, then do one of the following, depending on
* which is most appropriate for the target:
* <ul>
* <li>If possible, <em>remove</em> that attribute from the target
* object entirely.</li>
* <li>Otherwise, <em>replace all of the current values</em> of that
* attribute in the target object with a single value of
* {@code null}.</li>
* </ul>
*
* @param objclass the type of object to modify. Will never be null.
* @param uid the uid of the object to modify. Will never be null.
* @param replaceAttributes set of new {@link org.identityconnectors.framework.common.objects.Attribute}. the values in this set
* represent the new, merged values to be applied to the object.
* This set may also include {@link org.identityconnectors.framework.common.objects.OperationalAttributes operational attributes}.
* Will never be null.
* @param options additional options that impact the way this operation is run.
* Will never be null.
* @return the {@link org.identityconnectors.framework.common.objects.Uid} of the updated object in case the update changes
* the formation of the unique identifier.
* @throws org.identityconnectors.framework.common.exceptions.UnknownUidException
* iff the {@link org.identityconnectors.framework.common.objects.Uid} does not exist on the resource.
*/
@Override
public Uid update(ObjectClass objclass, Uid uid, Set<Attribute> replaceAttributes, OperationOptions options) {
return null;
}
}