/*
* Copyright (c) 2010-2017 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.midpoint.provisioning.api;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.xml.namespace.QName;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.prism.Objectable;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.query.ObjectPaging;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.ProvisioningDiag;
import com.evolveum.midpoint.schema.ResourceShadowDiscriminator;
import com.evolveum.midpoint.schema.ResultHandler;
import com.evolveum.midpoint.schema.SearchResultList;
import com.evolveum.midpoint.schema.SearchResultMetadata;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.ConnectorTestOperation;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.statistics.ConnectorOperationalStatus;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.CommunicationException;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SecurityViolationException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorHostType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationProvisioningScriptsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ProvisioningScriptType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
/**
* <p>Provisioning Service Interface.</p>
* <p>
* Status: public
* Stability: STABLE, only compatible changes are expected
* @version 3.4
* @author Radovan Semancik
* </p>
* <p>
* This service retrieves information about resource objects and resources
* and handles changes to resource objects. Implementations of this interface
* will apply the changes to accounts, groups and other similar objects to the
* target resources. It also provides information about connectors and similar
* configuration of access to the resources.
* </p>
* <p>
* Supported object types:
* <ul>
* <li>Resource</li>
* <li>ResourceObjectShadow and all sub-types</li>
* <li>Connector</li>
* </ul>
* Supported extra data types:
* <ul>
* <li>Resource Objects (Resource Schema)</li>
* </ul>
* </p>
* <p>
* TODO: better documentation
* </p>
*/
public interface ProvisioningService {
/**
* Returns object for provided OID.
*
* Must fail if object with the OID does not exists.
*
* Resource Object Shadows: The resource object shadow attributes may be
* retrieved from the local database, directly form the resource or a
* combination of both. The retrieval may fail due to resource failure,
* network failure or similar external cases. The retrieval may also take
* relatively long time (e.g. until it times out).
*
* @param type the type (class) of object to get
* @param oid
* OID of the object to get
* @param parentResult
* parent OperationResult (in/out)
* @return Object fetched from repository and/or resource
*
* @throws ObjectNotFoundException
* requested object does not exist
* @throws CommunicationException
* error communicating with the resource
* @throws SchemaException
* error dealing with resource schema
* @throws ConfigurationException
* Wrong resource or connector configuration
* @throws SecurityViolationException
* Security violation while communicating with the connector or processing provisioning policies
* @throws IllegalArgumentException
* wrong OID format, etc.
* @throws GenericConnectorException
* unknown connector framework error
*/
<T extends ObjectType> PrismObject<T> getObject(Class<T> type, String oid, Collection<SelectorOptions<GetOperationOptions>> options, Task task, OperationResult parentResult)
throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException,
SecurityViolationException;
/**
* Add new object.
*
* The OID provided in the input message may be empty. In that case the OID
* will be assigned by the implementation of this method and it will be
* provided as return value.
*
* This operation should fail if such object already exists (if object with
* the provided OID already exists).
*
* The operation may fail if provided OID is in an unusable format for the
* storage. Generating own OIDs and providing them to this method is not
* recommended for normal operation.
*
* Should be atomic. Should not allow creation of two objects with the same
* OID (even if created in parallel).
*
* The operation may fail if the object to be created does not conform to
* the underlying schema of the storage system or the schema enforced by the
* implementation.
*
* @param object
* object to create
* @param scripts
* scripts to execute before/after the operation
* @param parentResult
* parent OperationResult (in/out)
* @return OID assigned to the created object
*
* @throws ObjectAlreadyExistsException
* object with specified identifiers already exists, cannot add
* @throws SchemaException
* error dealing with resource schema, e.g. schema violation
* @throws CommunicationException
* error communicating with the resource
* @throws ObjectNotFoundException appropriate connector object was not found
* @throws ConfigurationException
* @throws IllegalArgumentException
* wrong OID format, etc.
* @throws GenericConnectorException
* unknown connector framework error
* @throws SecurityViolationException
* Security violation while communicating with the connector or processing provisioning policies
*/
<T extends ObjectType> String addObject(PrismObject<T> object, OperationProvisioningScriptsType scripts, ProvisioningOperationOptions options,
Task task, OperationResult parentResult)
throws ObjectAlreadyExistsException, SchemaException, CommunicationException, ObjectNotFoundException,
ConfigurationException, SecurityViolationException;
/**
* Collect external changes on a resource and call the business logic with
* the accumulated change data.
*
* This method will be invoked by scheduler/sync thread.
*
* TODO: Better description
*
* @param resourceOid
* OID of the resource for which to attempt synchronization
* @param parentResult
* parent OperationResult (in/out)
* @return the number of processed changes
* @throws ObjectNotFoundException
* some of key objects (resource, task, ...) do not exist
* @throws CommunicationException
* error communicating with the resource
* @throws SchemaException
* error dealing with resource schema
* @throws ConfigurationException
* @throws SecurityViolationException
* Security violation while communicating with the connector or processing provisioning policies
* @throws GenericConnectorException
* unknown connector framework error
*/
int synchronize(ResourceShadowDiscriminator shadowCoordinates, Task task, OperationResult parentResult) throws ObjectNotFoundException,
CommunicationException, SchemaException, ConfigurationException, SecurityViolationException;
/**
* Search for objects. Searches through all object types. Returns a list of
* objects that match search criteria.
*
* Returns empty list if object type is correct but there are no objects of
* that type.
*
* Should fail if object type is wrong. Should fail if unknown property is
* specified in the query.
*
* @param paging
* paging specification to limit operation result (optional)
* @param query
* search query
* @param task
*@param parentResult
* parent OperationResult (in/out) @return all objects of specified type that match search criteria (subject
* to paging)
*
* @throws IllegalArgumentException
* wrong object type
* @throws GenericConnectorException
* unknown connector framework error
* @throws SchemaException
* unknown property used in search query
* @throws ConfigurationException
* @throws SecurityViolationException
* Security violation while communicating with the connector or processing provisioning policies
*/
<T extends ObjectType> SearchResultList<PrismObject<T>> searchObjects(Class<T> type, ObjectQuery query, Collection<SelectorOptions<GetOperationOptions>> options, Task task, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException,
SecurityViolationException;
/**
* Options: if noFetch or raw, we count only shadows from the repository.
*/
<T extends ObjectType> Integer countObjects(Class<T> type, ObjectQuery query, Collection<SelectorOptions<GetOperationOptions>> options, Task task, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException,
SecurityViolationException;
/**
* Search for objects iteratively. Searches through all object types. Calls a
* specified handler for each object found.
*
* If nothing is found the handler is not called and the operation returns.
*
* Should fail if object type is wrong. Should fail if unknown property is
* specified in the query.
*
* @param query
* search query
* @param handler
* result handler
* @param task
*@param parentResult
* parent OperationResult (in/out)
* @throws IllegalArgumentException
* wrong object type
* @throws GenericConnectorException
* unknown connector framework error
* @throws SchemaException
* unknown property used in search query
* @throws ObjectNotFoundException appropriate connector object was not found
* @throws ConfigurationException
* @throws SecurityViolationException
* Security violation while communicating with the connector or processing provisioning policies
*/
<T extends ObjectType> SearchResultMetadata searchObjectsIterative(Class<T> type, ObjectQuery query, Collection<SelectorOptions<GetOperationOptions>> options,
final ResultHandler<T> handler, Task task, final OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException;
/**
* Modifies object using relative change description. Must fail if user with
* provided OID does not exists. Must fail if any of the described changes
* cannot be applied. Should be atomic.
*
* If two or more modify operations are executed in parallel, the operations
* should be merged. In case that the operations are in conflict (e.g. one
* operation adding a value and the other removing the same value), the
* result is not deterministic.
*
* The operation may fail if the modified object does not conform to the
* underlying schema of the storage system or the schema enforced by the
* implementation.
*
* TODO: optimistic locking
*
* @param scripts
* scripts that should be executed before of after operation
* @param parentResult
* parent OperationResult (in/out)
*
* @throws ObjectNotFoundException
* specified object does not exist
* @throws SchemaException
* resulting object would violate the schema
* @throws IllegalArgumentException
* wrong OID format, described change is not applicable
* @throws GenericConnectorException
* unknown connector framework error
* @throws SecurityViolationException
* Security violation while communicating with the connector or processing provisioning policies
* @throws ObjectAlreadyExistsException
* if resulting object would have name which already exists in another object of the same type
*/
<T extends ObjectType> String modifyObject(Class<T> type, String oid, Collection<? extends ItemDelta> modifications,
OperationProvisioningScriptsType scripts, ProvisioningOperationOptions options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException,
CommunicationException, ConfigurationException, SecurityViolationException, ObjectAlreadyExistsException;
/**
* <p>Deletes object with specified OID.</p>
* <p>
* Must fail if object with specified OID
* does not exists. Should be atomic.
* </p>
*
* @param oid
* OID of object to delete
* @param scripts
* scripts that should be executed before of after operation
* @param parentResult
* parent OperationResult (in/out)
*
* @throws ObjectNotFoundException
* specified object does not exist
* @throws ConfigurationException
* @throws SecurityViolationException
* Security violation while communicating with the connector or processing provisioning policies
* @throws IllegalArgumentException
* wrong OID format, described change is not applicable
* @throws GenericConnectorException
* unknown connector framework error
*/
<T extends ObjectType> void deleteObject(Class<T> type, String oid, ProvisioningOperationOptions option, OperationProvisioningScriptsType scripts, Task task, OperationResult parentResult)
throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException;
/**
* Executes a single provisioning script.
*
* @param script
* script to execute
* @param parentResult
* parent OperationResult (in/out)
*
* @throws ObjectNotFoundException
* specified object does not exist
* @throws SchemaException
* resulting object would violate the schema
* @throws IllegalArgumentException
* wrong OID format, described change is not applicable
* @throws GenericConnectorException
* unknown connector framework error
* @throws SecurityViolationException
* Security violation while communicating with the connector or processing provisioning policies
* @throws ObjectAlreadyExistsException
* if resulting object would have name which already exists in another object of the same type
*/
<T extends ObjectType> void executeScript(String resourceOid, ProvisioningScriptType script, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException,
CommunicationException, ConfigurationException, SecurityViolationException, ObjectAlreadyExistsException;
/**
* Test the resource connection and basic resource connector functionality.
*
* This operation will NOT throw exception in case the resource connection
* fails. It such case it will indicate the failure in the return message,
* but the operation itself succeeds. The operations fails only if the
* provided arguments are wrong, in case of system error, system
* misconfiguration, etc.
*
* The operation codes in the return value are defined by ConnectorTestOperation enumeration class.
*
* @param resourceOid
* OID of resource to test
* @return results of executed tests
*
* @throws ObjectNotFoundException
* specified object does not exist
* @throws IllegalArgumentException
* wrong OID format
* @throws GenericConnectorException
* unknown connector framework error
*
* @see ConnectorTestOperation
*/
OperationResult testResource(String resourceOid) throws ObjectNotFoundException;
/**
* Discovers local or remote connectors.
*
* The operation will try to search for new connectors. It works either on local host (hostType is null)
* or on a remote host (hostType is not null). All discovered connectors are stored in the repository.
*
* It returns connectors that were discovered: those that were not in the repository before invocation
* of this operation.
*
* @param hostType definition of a connector host or null
* @param parentResult parentResult parent OperationResult (in/out)
* @return discovered connectors
* @throws CommunicationException error connecting to a remote host
*/
Set<ConnectorType> discoverConnectors(ConnectorHostType hostType, OperationResult parentResult) throws CommunicationException;
List<ConnectorOperationalStatus> getConnectorOperationalStatus(String resourceOid, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException;
/**
* Lists resource objects.
*
* This method differs from other method in this interface as it works with resource objects directly.
* It returns resource objects in a form of "detached shadow", that means fully-populated shadow objects
* with no OID. The results of this method may not be stored in the repository.
*
* The purpose of this method is to work directly with the resource without the potential problems of
* provisioning implementation. E.g. it may be used to test resource connectivity or correctness of resource
* setup. It may also be used to reach object types that are not directly supported as "shadows" by the provisioning
* implementation.
*
* @param resourceOid OID of the resource to fetch objects from
* @param objectClass Object class of the objects to fetch
* @param paging paging specification to limit operation result (optional)
* @param task
*@param parentResult
* parent OperationResult (in/out) @return resource objects in a form of "detached shadows"
* @throws ObjectNotFoundException specified resource object does not exist
* @throws SchemaException error handling resource schema
* @throws CommunicationException error communicating with the resource
*/
List<PrismObject<? extends ShadowType>> listResourceObjects(String resourceOid, QName objectClass, ObjectPaging paging,
Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException;
/**
* Makes sure that the shadow is in accord with the reality. If there are any unfinished operations associated with the shadow
* then this method will try to finish them. If there are pending (async) operations then this method will update their status.
* And so on. However, this is NOT reconciliation function that will make sure that the resource object attributes are OK
* with all the policies. This is just a provisioning-level operation.
*/
void refreshShadow(PrismObject<ShadowType> shadow, ProvisioningOperationOptions options, Task task, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException,
ObjectAlreadyExistsException, SecurityViolationException;
/**
* Applies appropriate definition to the shadow/resource delta.
*/
<T extends ObjectType> void applyDefinition(ObjectDelta<T> delta, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException;
/**
* Applies appropriate definition to the shadow/resource delta (uses provided object to get necessary information)
*/
<T extends ObjectType> void applyDefinition(ObjectDelta<T> delta, Objectable object, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException;
/**
* Applies appropriate definition to the shadow.
*/
<T extends ObjectType> void applyDefinition(PrismObject<T> object, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException;
/**
* Applies appropriate definition to the query.
*/
<T extends ObjectType> void applyDefinition(Class<T> type, ObjectQuery query, OperationResult parentResult)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException;
/**
* Runs a short, non-destructive internal provisioning test. It tests provisioning framework and
* general setup. Use ModelService.testResource for testing individual resource configurations.
*/
void provisioningSelfTest(OperationResult parentTestResult, Task task);
/**
* Returns a diagnostic information.
* @see com.evolveum.midpoint.schema.ProvisioningDiag
* @return
*/
ProvisioningDiag getProvisioningDiag();
/**
* Finish initialization of provisioning system.
*
* The implementation may execute resource-intensive tasks in this method. All the dependencies should be already
* constructed, properly wired and initialized. Also logging and other infrastructure should be already set up.
*/
void postInit(OperationResult parentResult);
ConstraintsCheckingResult checkConstraints(RefinedObjectClassDefinition shadowDefinition,
PrismObject<ShadowType> shadowObject,
ResourceType resourceType,
String shadowOid,
ResourceShadowDiscriminator resourceShadowDiscriminator,
ConstraintViolationConfirmer constraintViolationConfirmer,
Task task, OperationResult parentResult) throws CommunicationException, ObjectAlreadyExistsException, SchemaException, SecurityViolationException, ConfigurationException, ObjectNotFoundException;
void enterConstraintsCheckerCache();
void exitConstraintsCheckerCache();
void shutdown();
}