/* * 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.midpoint.provisioning.consistency.impl; import java.util.Collection; import com.evolveum.midpoint.provisioning.impl.ConstraintsChecker; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.PropertyDelta; import com.evolveum.midpoint.provisioning.api.ProvisioningService; import com.evolveum.midpoint.provisioning.consistency.api.ErrorHandler; import com.evolveum.midpoint.provisioning.ucf.api.GenericFrameworkException; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.DeltaConvertor; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.schema.util.ResourceTypeUtil; import com.evolveum.midpoint.schema.util.ShadowUtil; 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.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; @Component public class GenericErrorHandler extends ErrorHandler{ private static final String COMPENSATE_OPERATION = GenericErrorHandler.class.getName()+".compensate"; private static final Trace LOGGER = TraceManager.getTrace(GenericErrorHandler.class); @Autowired(required = true) private ProvisioningService provisioningService; // @Autowired(required = true) // private ShadowCacheReconciler shadowCacheFinisher; @Autowired @Qualifier("cacheRepositoryService") private RepositoryService cacheRepositoryService; // @Autowired // private OperationFinisher operationFinisher; @Override public <T extends ShadowType> T handleError(T shadow, FailedOperation op, Exception ex, boolean doDiscovery, boolean compensate, Task task, OperationResult parentResult) throws SchemaException, GenericFrameworkException, CommunicationException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, SecurityViolationException { if (!doDiscovery) { parentResult.recordFatalError(ex); if (ex instanceof GenericFrameworkException) { throw (GenericFrameworkException)ex; } else { throw new GenericFrameworkException(ex.getMessage(), ex); } } // OperationResult result = OperationResult.createOperationResult(shadow.getResult()); String operation = (shadow.getFailedOperationType() == null ? "null" : shadow.getFailedOperationType().name()); OperationResult result = parentResult.createSubresult(COMPENSATE_OPERATION); result.addContext("compensatedOperation", operation); result.addContext("operationType",op.name()); result.addParam("shadow", shadow); result.addParam("currentOperation", op); result.addParam("reconciled", true); switch (op) { case GET: if (ShadowUtil.isDead(shadow) || ResourceTypeUtil.isDown(shadow.getResource()) || !compensate) { result.recordStatus(OperationResultStatus.PARTIAL_ERROR, "Unable to get object from the resource. Probably it has not been created yet because of previous unavailability of the resource."); result.computeStatus(); shadow.setFetchResult(parentResult.createOperationResultType()); return shadow; } if (shadow.getFailedOperationType() == null) { String message = "Generic error in the connector. Can't process shadow " + ObjectTypeUtil.toShortString(shadow) + ": " + ex.getMessage(); result.recordFatalError(message, ex); throw new GenericFrameworkException(message, ex); } try { //ProvisioningOperationOptions.createCompletePostponed(false); provisioningService.refreshShadow(shadow.asPrismObject(), null, task, result); result.computeStatus(); if (result.isSuccess()) { LOGGER.trace("Postponed operation was finished successfully while getting shadow. Getting new object."); PrismObject prismShadow = provisioningService.getObject(shadow.getClass(), shadow.getOid(), null, task, result); if (!prismShadow.hasCompleteDefinition()){ LOGGER.trace("applying definitions to shadow"); provisioningService.applyDefinition(prismShadow, result); } if (LOGGER.isTraceEnabled()) { LOGGER.trace("Got {} after finishing postponed operation.", prismShadow.debugDump()); } shadow = (T) prismShadow.asObjectable(); } // } catch(Exception e){ // result.recordFatalError("Could not finish operation " + operation + ". Reason: " + e.getMessage())); // // just throw the origin exception // throw new GenericFrameworkException(ex); } finally { result.computeStatus(); } return shadow; case MODIFY: if (shadow.getFailedOperationType() == null) { String message = "Generic error in the connector. Can't process shadow " + ObjectTypeUtil.toShortString(shadow) + ". "; result.recordFatalError(message, ex); throw new GenericFrameworkException(message, ex); } // get the modifications from the shadow before the account // is created, because after successful creation of account, // the modification will be lost Collection<? extends ItemDelta> modifications = null; if (shadow.getObjectChange() != null) { ObjectDeltaType deltaType = shadow.getObjectChange(); modifications = DeltaConvertor.toModifications(deltaType.getItemDelta(), shadow .asPrismObject().getDefinition()); } PropertyDelta.applyTo(modifications, shadow.asPrismObject()); provisioningService.refreshShadow(shadow.asPrismObject(), null, task, result); result.computeStatus(); if (!result.isSuccess()) { // account wasn't created, probably resource is // still down, or there is other reason.just save the // pending modifications to the shadow in the // repository..next time by processing this shadow, we can try again // TODO: probably there is a need to union current changes with previous ConstraintsChecker.onShadowModifyOperation(modifications); cacheRepositoryService.modifyObject(ShadowType.class, shadow.getOid(), modifications, result); result.recordHandledError("Modifications not applied to the object, because resource is unreachable. They are stored to the shadow and will be applied when the resource goes online."); } return shadow; case DELETE: cacheRepositoryService.deleteObject(shadow.getClass(), shadow.getOid(), result); result.recordStatus(OperationResultStatus.HANDLED_ERROR, "Object has been not created on the resource yet. Shadow deleted from the repository"); return shadow; default: result.recordFatalError("Can't process " + ObjectTypeUtil.toShortString(shadow) + ": "+ex.getMessage(), ex); if (shadow.getOid() == null){ throw new GenericFrameworkException("Can't process " + ObjectTypeUtil.toShortString(shadow) + ": "+ex.getMessage(), ex); } Collection<ItemDelta> modification = createAttemptModification(shadow, null); ConstraintsChecker.onShadowModifyOperation(modification); cacheRepositoryService.modifyObject(shadow.asPrismObject().getCompileTimeClass(), shadow.getOid(), modification, parentResult); String message = "Can't process " + ObjectTypeUtil.toShortString(shadow) + ". "; result.recordFatalError(message, ex); throw new GenericFrameworkException(message, ex); } } }