/*
* Copyright (c) 2010-2013 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.wf.impl.util;
import com.evolveum.midpoint.model.api.ModelAuthorizationAction;
import com.evolveum.midpoint.model.api.ModelInteractionService;
import com.evolveum.midpoint.model.api.context.ModelContext;
import com.evolveum.midpoint.model.api.context.ModelElementContext;
import com.evolveum.midpoint.model.api.util.DeputyUtils;
import com.evolveum.midpoint.model.common.SystemObjectCache;
import com.evolveum.midpoint.model.impl.lens.LensFocusContext;
import com.evolveum.midpoint.model.impl.lens.LensProjectionContext;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.DeltaConvertor;
import com.evolveum.midpoint.schema.ObjectTreeDeltas;
import com.evolveum.midpoint.schema.ResourceShadowDiscriminator;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.schema.util.OidUtil;
import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.security.api.SecurityEnforcer;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.task.api.TaskManager;
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.wf.impl.WfConfiguration;
import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngine;
import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames;
import com.evolveum.midpoint.wf.impl.processes.common.LightweightObjectRef;
import com.evolveum.midpoint.wf.impl.processors.BaseModelInvocationProcessingHelper;
import com.evolveum.midpoint.wf.impl.processors.primary.WfPrepareChildOperationTaskHandler;
import com.evolveum.midpoint.wf.impl.processors.primary.WfPrepareRootOperationTaskHandler;
import com.evolveum.midpoint.wf.util.ApprovalUtils;
import com.evolveum.midpoint.wf.util.ChangesByState;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.TaskService;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.task.IdentityLink;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import java.util.*;
import java.util.stream.Collectors;
import static com.evolveum.midpoint.prism.delta.ChangeType.ADD;
import static com.evolveum.midpoint.schema.ObjectTreeDeltas.fromObjectTreeDeltasType;
import static org.apache.commons.collections.CollectionUtils.addIgnoreNull;
/**
* @author mederly
*/
@Component
public class MiscDataUtil {
private static final transient Trace LOGGER = TraceManager.getTrace(MiscDataUtil.class);
@Autowired
@Qualifier("cacheRepositoryService")
private RepositoryService repositoryService;
@Autowired
private PrismContext prismContext;
@Autowired
private TaskManager taskManager;
@Autowired
private SecurityEnforcer securityEnforcer;
@Autowired
private WfConfiguration wfConfiguration;
@Autowired
private ActivitiEngine activitiEngine;
@Autowired
private BaseModelInvocationProcessingHelper baseModelInvocationProcessingHelper;
public static ObjectReferenceType toObjectReferenceType(LightweightObjectRef ref) {
if (ref != null) {
return ref.toObjectReferenceType();
} else {
return null;
}
}
//region ========================================================================== Miscellaneous
public PrismObject<UserType> getUserByOid(String oid, OperationResult result) {
if (oid == null) {
return null;
}
try {
return repositoryService.getObject(UserType.class, oid, null, result);
} catch (ObjectNotFoundException e) {
// there should be a note in result by now
LoggingUtils.logException(LOGGER, "Couldn't get user {} details because it couldn't be found", e, oid);
return null;
} catch (SchemaException e) {
// there should be a note in result by now
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get user {} details due to schema exception", e, oid);
return null;
}
}
// returns oid when user cannot be retrieved
public String getUserNameByOid(String oid, OperationResult result) {
try {
PrismObject<UserType> user = repositoryService.getObject(UserType.class, oid, null, result);
return user.asObjectable().getName().getOrig();
} catch (ObjectNotFoundException e) {
// there should be a note in result by now
LoggingUtils.logException(LOGGER, "Couldn't get user {} details because it couldn't be found", e, oid);
return oid;
} catch (SchemaException e) {
// there should be a note in result by now
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get user {} details due to schema exception", e, oid);
return oid;
}
}
public ObjectDelta getFocusPrimaryDelta(WfContextType workflowContext, boolean mayBeNull) throws JAXBException, SchemaException {
ObjectDeltaType objectDeltaType = getFocusPrimaryObjectDeltaType(workflowContext, mayBeNull);
return objectDeltaType != null ? DeltaConvertor.createObjectDelta(objectDeltaType, prismContext) : null;
}
// mayBeNull=false means that the corresponding variable must be present (not that focus must be non-null)
// TODO: review/correct this!
public ObjectDeltaType getFocusPrimaryObjectDeltaType(WfContextType workflowContext, boolean mayBeNull) throws JAXBException, SchemaException {
ObjectTreeDeltasType deltas = getObjectTreeDeltaType(workflowContext, mayBeNull);
return deltas != null ? deltas.getFocusPrimaryDelta() : null;
}
public ObjectTreeDeltasType getObjectTreeDeltaType(WfContextType workflowContext, boolean mayBeNull) throws SchemaException {
WfProcessorSpecificStateType state = workflowContext.getProcessorSpecificState();
if (mayBeNull && state == null) {
return null;
}
if (!(state instanceof WfPrimaryChangeProcessorStateType)) {
throw new IllegalStateException("Expected WfPrimaryChangeProcessorStateType but got " + state);
}
return ((WfPrimaryChangeProcessorStateType) state).getDeltasToProcess();
}
public static String serializeObjectToXml(PrismObject<? extends ObjectType> object) {
return serializeObjectToXml(object, object.getPrismContext());
}
public static String serializeObjectToXml(PrismObject<? extends ObjectType> object, PrismContext prismContext) {
try {
return prismContext.serializeObjectToString(object, PrismContext.LANG_XML);
} catch (SchemaException e) {
throw new SystemException("Couldn't serialize a PrismObject " + object + " into XML", e);
}
}
public static String serializeContainerableToXml(Containerable containerable, PrismContext prismContext) {
try {
PrismContainerValue value = containerable.asPrismContainerValue();
return prismContext.xmlSerializer().serialize(value, value.getContainer().getElementName());
} catch (SchemaException e) {
throw new SystemException("Couldn't serialize a Containerable " + containerable + " into XML", e);
}
}
public static ObjectType deserializeObjectFromXml(String xml, PrismContext prismContext) {
try {
return (ObjectType) prismContext.parserFor(xml).xml().parse().asObjectable();
} catch (SchemaException e) {
throw new SystemException("Couldn't deserialize a PrismObject from XML", e);
}
}
// public static PrismContainer deserializeContainerFromXml(String xml, PrismContext prismContext) {
// try {
// return prismContext.processorFor(xml).xml().unmarshallContainer(null); // TODO will 'null' work?
// } catch (SchemaException e) {
// throw new SystemException("Couldn't deserialize a Containerable from XML", e);
// }
// }
public void resolveAssignmentTargetReferences(PrismObject<? extends UserType> object, OperationResult result) {
for (AssignmentType assignmentType : object.asObjectable().getAssignment()) {
if (assignmentType.getTarget() == null && assignmentType.getTargetRef() != null) {
PrismObject<? extends ObjectType> target = null;
try {
target = repositoryService.getObject(ObjectType.class, assignmentType.getTargetRef().getOid(), null, result);
assignmentType.setTarget(target.asObjectable());
} catch (ObjectNotFoundException e) {
LoggingUtils.logException(LOGGER, "Couldn't resolve assignment " + assignmentType, e);
} catch (SchemaException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't resolve assignment " + assignmentType, e);
}
}
}
}
/**
* Retrieves focus object name from the model context.
*/
public static String getFocusObjectName(ModelContext<? extends ObjectType> modelContext) {
ObjectType object = getFocusObjectNewOrOld(modelContext);
return object.getName() != null ? object.getName().getOrig() : null;
}
public static String getFocusObjectOid(ModelContext<?> modelContext) {
ModelElementContext<?> fc = modelContext.getFocusContext();
if (fc.getObjectNew() != null && fc.getObjectNew().getOid() != null) {
return fc.getObjectNew().getOid();
} else if (fc.getObjectOld() != null && fc.getObjectOld().getOid() != null) {
return fc.getObjectOld().getOid();
} else {
return null;
}
}
public static ObjectType getFocusObjectNewOrOld(ModelContext<? extends ObjectType> modelContext) {
ModelElementContext<? extends ObjectType> fc = modelContext.getFocusContext();
PrismObject<? extends ObjectType> prism = fc.getObjectNew() != null ? fc.getObjectNew() : fc.getObjectOld();
if (prism == null) {
throw new IllegalStateException("No object (new or old) in model context");
}
return prism.asObjectable();
}
public Task getShadowTask(Map<String, Object> variables, OperationResult result) throws SchemaException, ObjectNotFoundException {
String oid = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID);
if (oid != null) {
return taskManager.getTask(oid, result);
} else {
return null;
}
}
@NotNull
public static String refToString(@NotNull ObjectReferenceType ref) {
return
(ref.getType() != null ? ref.getType().getLocalPart() : UserType.COMPLEX_TYPE.getLocalPart())
+ CommonProcessVariableNames.TYPE_NAME_SEPARATOR
+ ref.getOid();
}
public static List<String> refsToStrings(@NotNull Collection<ObjectReferenceType> refs) {
return refs.stream().map(r -> refToString(r)).collect(Collectors.toList());
}
@NotNull
public static List<String> prismRefsToStrings(Collection<PrismReferenceValue> refs) {
List<String> rv = new ArrayList<>();
for (PrismReferenceValue ref : refs) {
addIgnoreNull(rv, refToString(ObjectTypeUtil.createObjectRef(ref)));
}
return rv;
}
@NotNull
public static ObjectReferenceType stringToRef(@NotNull String s) {
String[] parts = s.split(CommonProcessVariableNames.TYPE_NAME_SEPARATOR);
if (parts.length == 0 || parts.length > 2) {
throw new IllegalArgumentException("Incorrect reference string representation: " + s);
} else if (parts.length == 1) {
return new ObjectReferenceType().oid(parts[0]).type(UserType.COMPLEX_TYPE);
} else {
// TODO support namespaces other than c:
QName type = StringUtils.isEmpty(parts[0]) ? UserType.COMPLEX_TYPE : new QName(SchemaConstants.NS_C, parts[0]);
return new ObjectReferenceType().oid(parts[1]).type(type);
}
}
public enum RequestedOperation {
COMPLETE(ModelAuthorizationAction.COMPLETE_ALL_WORK_ITEMS, null),
DELEGATE(ModelAuthorizationAction.DELEGATE_ALL_WORK_ITEMS, ModelAuthorizationAction.DELEGATE_OWN_WORK_ITEMS);
ModelAuthorizationAction actionAll, actionOwn;
RequestedOperation(ModelAuthorizationAction actionAll, ModelAuthorizationAction actionOwn) {
this.actionAll = actionAll;
this.actionOwn = actionOwn;
}
}
public boolean isAuthorized(WorkItemType workItem, RequestedOperation operation) {
MidPointPrincipal principal;
try {
principal = securityEnforcer.getPrincipal();
} catch (SecurityViolationException e) {
return false;
}
if (principal.getOid() == null) {
return false;
}
try {
if (securityEnforcer.isAuthorized(operation.actionAll.getUrl(), null, null, null, null, null)) {
return true;
}
if (operation.actionOwn != null && !securityEnforcer.isAuthorized(operation.actionOwn.getUrl(), null, null, null, null, null)) {
return false;
}
} catch (SchemaException e) {
throw new SystemException(e.getMessage(), e);
}
for (ObjectReferenceType assignee : workItem.getAssigneeRef()) {
if (isEqualOrDeputyOf(principal, assignee.getOid())) {
return true;
}
}
return isAmongCandidates(principal, workItem.getExternalId());
}
public boolean isEqualOrDeputyOf(MidPointPrincipal principal, String eligibleUserOid) {
return principal.getOid().equals(eligibleUserOid)
|| DeputyUtils.isDelegationPresent(principal.getUser(), eligibleUserOid);
}
public WfConfigurationType getWorkflowConfiguration(SystemObjectCache systemObjectCache, OperationResult result) throws SchemaException {
PrismObject<SystemConfigurationType> systemConfiguration = systemObjectCache.getSystemConfiguration(result);
if (systemConfiguration == null) {
return null;
}
return systemConfiguration.asObjectable().getWorkflowConfiguration();
}
// principal != null, principal.getOid() != null, principal.getUser() != null
private boolean isAmongCandidates(MidPointPrincipal principal, String taskId) {
String currentUserOid = principal.getOid();
List<IdentityLink> identityLinks;
try {
TaskService taskService = activitiEngine.getTaskService();
identityLinks = taskService.getIdentityLinksForTask(taskId);
} catch (ActivitiException e) {
throw new SystemException("Couldn't determine user authorization, because the task candidate users and groups couldn't be retrieved: " + e.getMessage(), e);
}
for (IdentityLink identityLink : identityLinks) {
if (identityLink.getUserId() != null && identityLink.getUserId().equals(currentUserOid)) {
return true;
}
if (identityLink.getGroupId() != null) {
if (isMemberOfActivitiGroup(principal.getUser(), identityLink.getGroupId())) {
return true;
}
}
}
return false;
}
public boolean isAuthorizedToClaim(WorkItemType workItem) {
return isAuthorizedToClaim(workItem.getExternalId());
}
public boolean isAuthorizedToClaim(String taskId) {
MidPointPrincipal principal;
try {
principal = securityEnforcer.getPrincipal();
} catch (SecurityViolationException e) {
return false;
}
String currentUserOid = principal.getOid();
if (currentUserOid == null) {
return false;
}
return isAmongCandidates(principal, taskId);
}
// todo move to something activiti-related
public static Map<String,FormProperty> formPropertiesAsMap(List<FormProperty> properties) {
Map<String,FormProperty> retval = new HashMap<String,FormProperty>();
for (FormProperty property : properties) {
retval.put(property.getId(), property);
}
return retval;
}
public boolean isMemberOfActivitiGroup(UserType userType, String activitiGroupId) {
ObjectReferenceType groupRef = stringToRef(activitiGroupId);
return userType.getRoleMembershipRef().stream().anyMatch(ref -> matches(groupRef, ref))
|| userType.getDelegatedRef().stream().anyMatch(ref -> matches(groupRef, ref));
}
public boolean matches(ObjectReferenceType groupRef, ObjectReferenceType targetRef) {
return (ObjectTypeUtil.isMembershipRelation(targetRef.getRelation())) // TODO reconsider if we allow managers here
&& targetRef.getOid().equals(groupRef.getOid());
}
public PrismObject resolveObjectReference(ObjectReferenceType ref, OperationResult result) {
return resolveObjectReference(ref, false, result);
}
public PrismObject resolveAndStoreObjectReference(ObjectReferenceType ref, OperationResult result) {
return resolveObjectReference(ref, true, result);
}
public void resolveAndStoreObjectReferences(@NotNull Collection<ObjectReferenceType> references, OperationResult result) {
references.forEach(ref -> resolveObjectReference(ref, true, result));
}
private PrismObject resolveObjectReference(ObjectReferenceType ref, boolean storeBack, OperationResult result) {
if (ref == null) {
return null;
}
if (ref.asReferenceValue().getObject() != null) {
return ref.asReferenceValue().getObject();
}
try {
PrismObject object = repositoryService.getObject((Class) prismContext.getSchemaRegistry().getCompileTimeClass(ref.getType()), ref.getOid(), null, result);
if (storeBack) {
ref.asReferenceValue().setObject(object);
}
return object;
} catch (ObjectNotFoundException e) {
// there should be a note in result by now
LoggingUtils.logException(LOGGER, "Couldn't get reference {} details because it couldn't be found", e, ref);
return null;
} catch (SchemaException e) {
// there should be a note in result by now
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get reference {} details due to schema exception", e, ref);
return null;
}
}
public ObjectReferenceType resolveObjectReferenceName(ObjectReferenceType ref, OperationResult result) {
if (ref == null || ref.getTargetName() != null) {
return ref;
}
PrismObject<?> object;
if (ref.asReferenceValue().getObject() != null) {
object = ref.asReferenceValue().getObject();
} else {
object = resolveObjectReference(ref, result);
if (object == null) {
return ref;
}
}
ref = ref.clone();
ref.setTargetName(PolyString.toPolyStringType(object.getName()));
return ref;
}
public void generateFocusOidIfNeeded(ModelContext<?> modelContext, ObjectDelta<? extends ObjectType> change) {
if (modelContext.getFocusContext().getOid() != null) {
return;
}
String newOid = OidUtil.generateOid();
LOGGER.trace("This is ADD operation with no focus OID provided. Generated new OID to be used: {}", newOid);
if (change.getChangeType() != ADD) {
throw new IllegalStateException("Change type is not ADD for no-oid focus situation: " + change);
} else if (change.getObjectToAdd() == null) {
throw new IllegalStateException("Object to add is null for change: " + change);
} else if (change.getObjectToAdd().getOid() != null) {
throw new IllegalStateException("Object to add has already an OID present: " + change);
}
change.getObjectToAdd().setOid(newOid);
((LensFocusContext<?>) modelContext.getFocusContext()).setOid(newOid);
}
public void generateProjectionOidIfNeeded(ModelContext<?> modelContext, ShadowType shadow, ResourceShadowDiscriminator rsd) {
if (shadow.getOid() != null) {
return;
}
String newOid = OidUtil.generateOid();
LOGGER.trace("This is ADD operation with no shadow OID for {} provided. Generated new OID to be used: {}", rsd, newOid);
shadow.setOid(newOid);
LensProjectionContext projCtx = ((LensProjectionContext) modelContext.findProjectionContext(rsd));
if (projCtx == null) {
throw new IllegalStateException("No projection context for " + rsd + " could be found");
} else if (projCtx.getOid() != null) {
throw new IllegalStateException("No projection context for " + rsd + " has already an OID: " + projCtx.getOid());
}
projCtx.setOid(newOid);
}
// TODO move somewhere else?
public ChangesByState getChangesByStateForChild(TaskType childTask, TaskType rootTask, ModelInteractionService modelInteractionService, PrismContext prismContext, OperationResult result)
throws SchemaException, ObjectNotFoundException {
ChangesByState rv = new ChangesByState(prismContext);
final WfContextType wfc = childTask.getWorkflowContext();
if (wfc != null && wfc.getProcessInstanceId() != null) {
Boolean isApproved = ApprovalUtils.approvalBooleanValueFromUri(wfc.getOutcome());
if (isApproved == null) {
if (wfc.getEndTimestamp() == null) {
recordChangesWaitingToBeApproved(rv, wfc, prismContext);
} else {
recordChangesCanceled(rv, wfc, prismContext);
}
} else if (isApproved) {
if (rootTask.getModelOperationContext() != null) {
// this is "execute after all approvals"
if (rootTask.getModelOperationContext().getState() == ModelStateType.FINAL) {
recordResultingChanges(rv.getApplied(), wfc, prismContext);
} else if (!containsHandler(rootTask, WfPrepareRootOperationTaskHandler.HANDLER_URI)) {
recordResultingChanges(rv.getBeingApplied(), wfc, prismContext);
} else {
recordResultingChanges(rv.getWaitingToBeApplied(), wfc, prismContext);
}
} else {
// "execute immediately"
if (childTask.getModelOperationContext().getState() == ModelStateType.FINAL) {
recordResultingChanges(rv.getApplied(), wfc, prismContext);
} else if (!containsHandler(childTask, WfPrepareChildOperationTaskHandler.HANDLER_URI)) {
recordResultingChanges(rv.getBeingApplied(), wfc, prismContext);
} else {
recordResultingChanges(rv.getWaitingToBeApplied(), wfc, prismContext);
}
}
} else {
recordChangesRejected(rv, wfc, prismContext);
}
}
return rv;
}
// TODO move somewhere else?
public ChangesByState getChangesByStateForRoot(TaskType rootTask, ModelInteractionService modelInteractionService, PrismContext prismContext, OperationResult result)
throws SchemaException, ObjectNotFoundException {
ChangesByState rv = new ChangesByState(prismContext);
recordChanges(rv, rootTask.getModelOperationContext(), modelInteractionService, result);
for (TaskType subtask : rootTask.getSubtask()) {
recordChanges(rv, subtask.getModelOperationContext(), modelInteractionService, result);
final WfContextType wfc = subtask.getWorkflowContext();
if (wfc != null && wfc.getProcessInstanceId() != null) {
Boolean isApproved = ApprovalUtils.approvalBooleanValueFromUri(wfc.getOutcome());
if (isApproved == null) {
if (wfc.getEndTimestamp() == null) {
recordChangesWaitingToBeApproved(rv, wfc, prismContext);
} else {
recordChangesCanceled(rv, wfc, prismContext);
}
} else if (isApproved) {
recordChangesApprovedIfNeeded(rv, subtask, rootTask, prismContext);
} else {
recordChangesRejected(rv, wfc, prismContext);
}
}
}
return rv;
}
private void recordChangesApprovedIfNeeded(ChangesByState rv, TaskType subtask, TaskType rootTask, PrismContext prismContext) throws SchemaException {
if (!containsHandler(rootTask, WfPrepareRootOperationTaskHandler.HANDLER_URI) &&
!containsHandler(subtask, WfPrepareChildOperationTaskHandler.HANDLER_URI)) {
return; // these changes were already incorporated into one of model contexts
}
if (subtask.getWorkflowContext().getProcessorSpecificState() instanceof WfPrimaryChangeProcessorStateType) {
WfPrimaryChangeProcessorStateType ps = (WfPrimaryChangeProcessorStateType) subtask.getWorkflowContext().getProcessorSpecificState();
rv.getWaitingToBeApplied().merge(fromObjectTreeDeltasType(ps.getResultingDeltas(), prismContext));
}
}
private boolean containsHandler(TaskType taskType, String handlerUri) {
if (handlerUri.equals(taskType.getHandlerUri())) {
return true;
}
if (taskType.getOtherHandlersUriStack() == null) {
return false;
}
for (UriStackEntry uriStackEntry : taskType.getOtherHandlersUriStack().getUriStackEntry()) {
if (handlerUri.equals(uriStackEntry.getHandlerUri())) {
return true;
}
}
return false;
}
private <F extends FocusType> void recordChanges(ChangesByState rv, LensContextType modelOperationContext, ModelInteractionService modelInteractionService,
OperationResult result) throws ObjectNotFoundException, SchemaException {
if (modelOperationContext == null) {
return;
}
ModelContext<F> modelContext = unwrapModelContext(modelOperationContext, modelInteractionService, result);
ObjectTreeDeltas<F> deltas = baseModelInvocationProcessingHelper.extractTreeDeltasFromModelContext(modelContext);
ObjectTreeDeltas<F> target;
switch (modelContext.getState()) {
case INITIAL:
case PRIMARY: target = rv.getWaitingToBeApplied(); break;
case SECONDARY: target = rv.getBeingApplied(); break;
case EXECUTION: // TODO reconsider this after EXECUTION and POSTEXECUTION states are really used
case POSTEXECUTION:
case FINAL: target = rv.getApplied(); break;
default: throw new IllegalStateException("Illegal model state: " + modelContext.getState());
}
target.merge(deltas);
}
protected void recordChangesWaitingToBeApproved(ChangesByState rv, WfContextType wfc, PrismContext prismContext)
throws SchemaException {
if (wfc.getProcessorSpecificState() instanceof WfPrimaryChangeProcessorStateType) {
WfPrimaryChangeProcessorStateType ps = (WfPrimaryChangeProcessorStateType) wfc.getProcessorSpecificState();
rv.getWaitingToBeApproved().merge(fromObjectTreeDeltasType(ps.getDeltasToProcess(), prismContext));
}
}
protected void recordChangesCanceled(ChangesByState rv, WfContextType wfc, PrismContext prismContext)
throws SchemaException {
if (wfc.getProcessorSpecificState() instanceof WfPrimaryChangeProcessorStateType) {
WfPrimaryChangeProcessorStateType ps = (WfPrimaryChangeProcessorStateType) wfc.getProcessorSpecificState();
rv.getCanceled().merge(fromObjectTreeDeltasType(ps.getDeltasToProcess(), prismContext));
}
}
private void recordChangesRejected(ChangesByState rv, WfContextType wfc, PrismContext prismContext) throws SchemaException {
if (wfc.getProcessorSpecificState() instanceof WfPrimaryChangeProcessorStateType) {
WfPrimaryChangeProcessorStateType ps = (WfPrimaryChangeProcessorStateType) wfc.getProcessorSpecificState();
if (ObjectTreeDeltas.isEmpty(ps.getResultingDeltas())) {
rv.getRejected().merge(fromObjectTreeDeltasType(ps.getDeltasToProcess(), prismContext));
} else {
// it's actually hard to decide what to display as 'rejected' - because the delta was partly approved
// however, this situation will not currently occur
}
}
}
private void recordResultingChanges(ObjectTreeDeltas<?> target, WfContextType wfc, PrismContext prismContext) throws SchemaException {
if (wfc.getProcessorSpecificState() instanceof WfPrimaryChangeProcessorStateType) {
WfPrimaryChangeProcessorStateType ps = (WfPrimaryChangeProcessorStateType) wfc.getProcessorSpecificState();
target.merge(fromObjectTreeDeltasType(ps.getResultingDeltas(), prismContext));
}
}
private ModelContext unwrapModelContext(LensContextType lensContextType, ModelInteractionService modelInteractionService, OperationResult result) throws
ObjectNotFoundException {
if (lensContextType != null) {
try {
return modelInteractionService.unwrapModelContext(lensContextType, result);
} catch (SchemaException | CommunicationException | ConfigurationException e) { // todo treat appropriately
throw new SystemException("Couldn't access model operation context in task: " + e.getMessage(), e);
}
} else {
return null;
}
}
}