/*
* 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.model.impl.visualizer;
import com.evolveum.midpoint.model.api.ModelService;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.provisioning.api.ProvisioningService;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static com.evolveum.midpoint.schema.GetOperationOptions.createNoFetch;
import static com.evolveum.midpoint.schema.SelectorOptions.createCollection;
import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.*;
/**
* Resolves definitions and old values.
* Currently NOT references.
*
* @author mederly
*/
@Component
public class Resolver {
private static final Trace LOGGER = TraceManager.getTrace(Resolver.class);
public static final String CLASS_DOT = Resolver.class.getName() + ".";
private static final String OP_RESOLVE = CLASS_DOT + "resolve";
@Autowired
private PrismContext prismContext;
@Autowired
private ModelService modelService;
@Autowired
private ProvisioningService provisioningService;
@Autowired
private Visualizer visualizer;
public <O extends ObjectType> void resolve(PrismObject<O> object, Task task, OperationResult result) throws SchemaException {
/*if (object.getDefinition() == null) */{
if (object == null) {
return;
}
Class<O> clazz = object.getCompileTimeClass();
if (clazz == null) {
warn(result, "Compile time class for " + toShortString(object) + " is not known");
} else {
PrismObjectDefinition<O> def = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(clazz);
if (def != null) {
if (ResourceType.class.isAssignableFrom(clazz) || ShadowType.class.isAssignableFrom(clazz)) {
try {
provisioningService.applyDefinition(object, result);
} catch (ObjectNotFoundException|CommunicationException|ConfigurationException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't apply definition on {} -- continuing with no definition", e,
ObjectTypeUtil.toShortString(object));
}
} else {
object.applyDefinition(def);
}
} else {
warn(result, "Definition for " + toShortString(object) + " couldn't be found");
}
}
}
}
public <O extends ObjectType> void resolve(ObjectDelta<O> objectDelta, Task task, OperationResult result) throws SchemaException {
if (objectDelta.isAdd()) {
resolve(objectDelta.getObjectToAdd(), task, result);
} else if (objectDelta.isDelete()) {
// nothing to do
} else {
PrismObject<O> originalObject = null;
boolean originalObjectFetched = false;
final Class<O> clazz = objectDelta.getObjectTypeClass();
boolean managedByProvisioning = ResourceType.class.isAssignableFrom(clazz) || ShadowType.class.isAssignableFrom(clazz);
PrismObjectDefinition<O> objectDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(clazz);
if (objectDefinition == null) {
warn(result, "Definition for " + clazz + " couldn't be found");
} else {
if (managedByProvisioning) {
try {
provisioningService.applyDefinition(objectDelta, result);
} catch (ObjectNotFoundException | CommunicationException | ConfigurationException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't apply definition on {} -- continuing with no definition", e, objectDelta);
}
}
}
for (ItemDelta itemDelta : objectDelta.getModifications()) {
if (objectDefinition != null && !managedByProvisioning) {
ItemDefinition<?> def = objectDefinition.findItemDefinition(itemDelta.getPath());
if (def != null) {
itemDelta.applyDefinition(def);
}
}
if (itemDelta.getEstimatedOldValues() == null) {
final String oid = objectDelta.getOid();
if (!originalObjectFetched && oid != null) {
try {
originalObject = modelService.getObject(clazz, oid, createCollection(createNoFetch()), task, result);
} catch (ObjectNotFoundException e) {
result.recordHandledError(e);
LoggingUtils.logExceptionOnDebugLevel(LOGGER, "Object {} does not exist", e, oid);
} catch (RuntimeException | SchemaException | ConfigurationException | CommunicationException | SecurityViolationException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't resolve object {}", e, oid);
warn(result, "Couldn't resolve object " + oid + ": " + e.getMessage(), e);
}
originalObjectFetched = true;
}
if (originalObject != null) {
Item<?,?> originalItem = originalObject.findItem(itemDelta.getPath());
if (originalItem != null) {
itemDelta.setEstimatedOldValues(new ArrayList(originalItem.getValues()));
}
}
}
}
}
}
private void warn(OperationResult result, String text, Exception e) {
result.createSubresult(OP_RESOLVE).recordWarning(text, e);
}
private void warn(OperationResult result, String text) {
result.createSubresult(OP_RESOLVE).recordWarning(text);
}
// TODO caching retrieved objects
public void resolve(List<ObjectDelta<? extends ObjectType>> deltas, Task task, OperationResult result) throws SchemaException {
for (ObjectDelta<? extends ObjectType> delta : deltas) {
resolve(delta, task, result);
}
}
}