/** * Copyright (c) 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.ucf.api.connectors; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.xml.namespace.QName; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.provisioning.ucf.api.AttributesToReturn; import com.evolveum.midpoint.provisioning.ucf.api.Change; import com.evolveum.midpoint.provisioning.ucf.api.ExecuteProvisioningScriptOperation; import com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException; import com.evolveum.midpoint.provisioning.ucf.api.ManagedConnector; import com.evolveum.midpoint.provisioning.ucf.api.Operation; import com.evolveum.midpoint.provisioning.ucf.api.PropertyModificationOperation; import com.evolveum.midpoint.provisioning.ucf.api.ResultHandler; import com.evolveum.midpoint.schema.SearchResultMetadata; import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; import com.evolveum.midpoint.schema.processor.ResourceAttribute; import com.evolveum.midpoint.schema.processor.ResourceObjectIdentification; import com.evolveum.midpoint.schema.processor.ResourceSchema; import com.evolveum.midpoint.schema.processor.SearchHierarchyConstraints; import com.evolveum.midpoint.schema.result.AsynchronousOperationQueryable; import com.evolveum.midpoint.schema.result.AsynchronousOperationResult; import com.evolveum.midpoint.schema.result.AsynchronousOperationReturnValue; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.statistics.ConnectorOperationalStatus; import com.evolveum.midpoint.task.api.StateReporter; 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.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.AbstractWriteCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ActivationStatusCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CreateCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.DeleteCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.PagedSearchCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.PasswordCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ReadCapabilityType; import com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.UpdateCapabilityType; /** * Common abstract superclass for all manual connectors. There are connectors that do not * talk to the resource directly. They rather rely on a human to manually execute the * modification task. These connectors are efficiently write-only. * * @author Radovan Semancik */ @ManagedConnector public abstract class AbstractManualConnectorInstance extends AbstractManagedConnectorInstance implements AsynchronousOperationQueryable { private static final String OPERATION_ADD = AbstractManualConnectorInstance.class.getName() + ".addObject"; private static final String OPERATION_MODIFY = AbstractManualConnectorInstance.class.getName() + ".modifyObject"; private static final String OPERATION_DELETE = AbstractManualConnectorInstance.class.getName() + ".deleteObject"; private static final com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ObjectFactory CAPABILITY_OBJECT_FACTORY = new com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.ObjectFactory(); private static final Trace LOGGER = TraceManager.getTrace(AbstractManualConnectorInstance.class); // test(), connect() and dispose() are lifecycle operations to be implemented in the subclasses // Operations to be implemented in the subclasses. These operations create the tickets. protected abstract String createTicketAdd(PrismObject<? extends ShadowType> object, Collection<Operation> additionalOperations, OperationResult result) throws CommunicationException, GenericFrameworkException, SchemaException, ObjectAlreadyExistsException, ConfigurationException; protected abstract String createTicketModify(ObjectClassComplexTypeDefinition objectClass, Collection<? extends ResourceAttribute<?>> identifiers, Collection<Operation> changes, OperationResult result) throws ObjectNotFoundException, CommunicationException, GenericFrameworkException, SchemaException, ObjectAlreadyExistsException, ConfigurationException; protected abstract String createTicketDelete(ObjectClassComplexTypeDefinition objectClass, Collection<? extends ResourceAttribute<?>> identifiers, OperationResult result) throws ObjectNotFoundException, CommunicationException, GenericFrameworkException, SchemaException, ConfigurationException; // TODO: operations to check ticket state @Override public AsynchronousOperationReturnValue<Collection<ResourceAttribute<?>>> addObject( PrismObject<? extends ShadowType> object, Collection<Operation> additionalOperations, StateReporter reporter, OperationResult parentResult) throws CommunicationException, GenericFrameworkException, SchemaException, ObjectAlreadyExistsException, ConfigurationException { OperationResult result = parentResult.createSubresult(OPERATION_ADD); String ticketIdentifier = null; try { ticketIdentifier = createTicketAdd(object, additionalOperations, result); } catch (CommunicationException | GenericFrameworkException | SchemaException | ObjectAlreadyExistsException | ConfigurationException | RuntimeException | Error e) { result.recordFatalError(e); throw e; } result.recordInProgress(); result.setAsynchronousOperationReference(ticketIdentifier); AsynchronousOperationReturnValue<Collection<ResourceAttribute<?>>> ret = new AsynchronousOperationReturnValue<>(); ret.setOperationResult(result); return ret; } @Override public AsynchronousOperationReturnValue<Collection<PropertyModificationOperation>> modifyObject( ObjectClassComplexTypeDefinition objectClass, Collection<? extends ResourceAttribute<?>> identifiers, Collection<Operation> changes, StateReporter reporter, OperationResult parentResult) throws ObjectNotFoundException, CommunicationException, GenericFrameworkException, SchemaException, SecurityViolationException, ObjectAlreadyExistsException, ConfigurationException { OperationResult result = parentResult.createSubresult(OPERATION_MODIFY); String ticketIdentifier = null; try { ticketIdentifier = createTicketModify(objectClass, identifiers, changes, result); } catch (ObjectNotFoundException | CommunicationException | GenericFrameworkException | SchemaException | ObjectAlreadyExistsException | ConfigurationException | RuntimeException | Error e) { result.recordFatalError(e); throw e; } result.recordInProgress(); result.setAsynchronousOperationReference(ticketIdentifier); AsynchronousOperationReturnValue<Collection<PropertyModificationOperation>> ret = new AsynchronousOperationReturnValue<>(); ret.setOperationResult(result); return ret; } @Override public AsynchronousOperationResult deleteObject(ObjectClassComplexTypeDefinition objectClass, Collection<Operation> additionalOperations, Collection<? extends ResourceAttribute<?>> identifiers, StateReporter reporter, OperationResult parentResult) throws ObjectNotFoundException, CommunicationException, GenericFrameworkException, SchemaException, ConfigurationException { OperationResult result = parentResult.createSubresult(OPERATION_DELETE); String ticketIdentifier = null; try { ticketIdentifier = createTicketDelete(objectClass, identifiers, result); } catch (ObjectNotFoundException | CommunicationException | GenericFrameworkException | SchemaException | ConfigurationException | RuntimeException | Error e) { result.recordFatalError(e); throw e; } result.recordInProgress(); result.setAsynchronousOperationReference(ticketIdentifier); return AsynchronousOperationResult.wrap(result); } @Override public Collection<Object> fetchCapabilities(OperationResult parentResult) throws CommunicationException, GenericFrameworkException, ConfigurationException { Collection<Object> capabilities = new ArrayList<>(); // caching-only read capabilities ReadCapabilityType readCap = new ReadCapabilityType(); readCap.setCachingOnly(true); capabilities.add(CAPABILITY_OBJECT_FACTORY.createRead(readCap)); CreateCapabilityType createCap = new CreateCapabilityType(); setManual(createCap); capabilities.add(CAPABILITY_OBJECT_FACTORY.createCreate(createCap)); UpdateCapabilityType updateCap = new UpdateCapabilityType(); setManual(updateCap); capabilities.add(CAPABILITY_OBJECT_FACTORY.createUpdate(updateCap)); DeleteCapabilityType deleteCap = new DeleteCapabilityType(); setManual(deleteCap); capabilities.add(CAPABILITY_OBJECT_FACTORY.createDelete(deleteCap)); ActivationCapabilityType activationCap = new ActivationCapabilityType(); ActivationStatusCapabilityType activationStatusCap = new ActivationStatusCapabilityType(); activationCap.setStatus(activationStatusCap); capabilities.add(CAPABILITY_OBJECT_FACTORY.createActivation(activationCap)); CredentialsCapabilityType credentialsCap = new CredentialsCapabilityType(); PasswordCapabilityType passwordCapabilityType = new PasswordCapabilityType(); credentialsCap.setPassword(passwordCapabilityType); capabilities.add(CAPABILITY_OBJECT_FACTORY.createCredentials(credentialsCap)); return capabilities; } private void setManual(AbstractWriteCapabilityType cap) { cap.setManual(true); } @Override public <T extends ShadowType> PrismObject<T> fetchObject(Class<T> type, ResourceObjectIdentification resourceObjectIdentification, AttributesToReturn attributesToReturn, StateReporter reporter, OperationResult parentResult) throws ObjectNotFoundException, CommunicationException, GenericFrameworkException, SchemaException, SecurityViolationException, ConfigurationException { // Read operations are not supported. We cannot really manually read the content of an off-line resource. return null; } @Override public <T extends ShadowType> SearchResultMetadata search( ObjectClassComplexTypeDefinition objectClassDefinition, ObjectQuery query, ResultHandler<T> handler, AttributesToReturn attributesToReturn, PagedSearchCapabilityType pagedSearchConfigurationType, SearchHierarchyConstraints searchHierarchyConstraints, StateReporter reporter, OperationResult parentResult) throws CommunicationException, GenericFrameworkException, SchemaException, SecurityViolationException, ObjectNotFoundException { // Read operations are not supported. We cannot really manually read the content of an off-line resource. return null; } @Override public int count(ObjectClassComplexTypeDefinition objectClassDefinition, ObjectQuery query, PagedSearchCapabilityType pagedSearchConfigurationType, StateReporter reporter, OperationResult parentResult) throws CommunicationException, GenericFrameworkException, SchemaException, UnsupportedOperationException { // Read operations are not supported. We cannot really manually read the content of an off-line resource. return 0; } @Override public ConnectorOperationalStatus getOperationalStatus() throws ObjectNotFoundException { ConnectorOperationalStatus opstatus = new ConnectorOperationalStatus(); opstatus.setConnectorClassName(this.getClass().getName()); return opstatus; } @Override public ResourceSchema fetchResourceSchema(List<QName> generateObjectClasses, OperationResult parentResult) throws CommunicationException, GenericFrameworkException, ConfigurationException { // Schema discovery is not supported. Schema must be defined manually. Or other connector has to provide it. return null; } @Override public <T> PrismProperty<T> fetchCurrentToken(ObjectClassComplexTypeDefinition objectClass, StateReporter reporter, OperationResult parentResult) throws CommunicationException, GenericFrameworkException { // not supported return null; } @Override public List<Change> fetchChanges(ObjectClassComplexTypeDefinition objectClass, PrismProperty<?> lastToken, AttributesToReturn attrsToReturn, StateReporter reporter, OperationResult parentResult) throws CommunicationException, GenericFrameworkException, SchemaException, ConfigurationException { // not supported return null; } @Override public PrismProperty<?> deserializeToken(Object serializedToken) { // not supported return null; } @Override public Object executeScript(ExecuteProvisioningScriptOperation scriptOperation, StateReporter reporter, OperationResult parentResult) throws CommunicationException, GenericFrameworkException { // not supported return null; } }