/*
* 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.util;
import com.evolveum.midpoint.common.crypto.CryptoUtil;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.common.refinery.RefinedResourceSchema;
import com.evolveum.midpoint.model.api.ModelExecuteOptions;
import com.evolveum.midpoint.model.common.expression.ExpressionVariables;
import com.evolveum.midpoint.model.common.expression.script.ScriptExpression;
import com.evolveum.midpoint.model.impl.ModelConstants;
import com.evolveum.midpoint.model.impl.expr.ExpressionEnvironment;
import com.evolveum.midpoint.model.impl.expr.ModelExpressionThreadLocalHolder;
import com.evolveum.midpoint.model.impl.importer.ObjectImporter;
import com.evolveum.midpoint.model.impl.lens.*;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.Visitor;
import com.evolveum.midpoint.prism.crypto.EncryptionException;
import com.evolveum.midpoint.prism.crypto.Protector;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.marshaller.QueryConvertor;
import com.evolveum.midpoint.prism.query.*;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.ObjectDeltaOperation;
import com.evolveum.midpoint.schema.ResourceShadowDiscriminator;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
import com.evolveum.midpoint.schema.constants.ObjectTypes;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.Handler;
import com.evolveum.midpoint.util.exception.ExpressionEvaluationException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType;
import com.evolveum.prism.xml.ns._public.types_3.EvaluationTimeType;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author lazyman
* @author semancik
*/
public final class Utils {
private static final Trace LOGGER = TraceManager.getTrace(Utils.class);
private static final String OPERATION_RESOLVE_REFERENCE = ObjectImporter.class.getName()
+ ".resolveReference";
@Deprecated // use RepositoryService.objectSearchIterative instead
public static <T extends ObjectType> void searchIterative(RepositoryService repositoryService, Class<T> type, ObjectQuery query,
Handler<PrismObject<T>> handler, int blockSize, OperationResult opResult) throws SchemaException {
ObjectQuery myQuery = query.clone();
// TODO: better handle original values in paging
ObjectPaging myPaging = ObjectPaging.createPaging(0, blockSize);
myQuery.setPaging(myPaging);
boolean cont = true;
while (cont) {
List<PrismObject<T>> objects = repositoryService.searchObjects(type, myQuery, null, opResult);
for (PrismObject<T> object: objects) {
if (!handler.handle(object)) {
return;
}
}
cont = objects.size() == blockSize;
myPaging.setOffset(myPaging.getOffset() + blockSize);
}
}
/**
* Resolves references contained in given PrismObject.
*
* @param object
* @param repository
* @param enforceReferentialIntegrity If true, missing reference causes fatal error when processing (if false, only warning is issued).
* @param forceFilterReevaluation If true, references are reevaluated even if OID is present. (Given that filter is present as well, of course.)
* @param prismContext
* @param result
*/
public static <T extends ObjectType> void resolveReferences(PrismObject<T> object, RepositoryService repository,
boolean enforceReferentialIntegrity, boolean forceFilterReevaluation, EvaluationTimeType resolutionTime,
boolean throwExceptionOnFailure,
PrismContext prismContext, OperationResult result) {
Visitor visitor = visitable -> {
if (!(visitable instanceof PrismReferenceValue)) {
return;
}
resolveRef((PrismReferenceValue)visitable, repository, enforceReferentialIntegrity, forceFilterReevaluation,
resolutionTime, prismContext, object.toString(), throwExceptionOnFailure, result);
};
object.accept(visitor);
}
/**
* Resolves references contained in ADD and REPLACE value sets for item modifications in a given ObjectDelta.
* (specially treats collisions with values to be deleted)
*/
public static <T extends ObjectType> void resolveReferences(ObjectDelta<T> objectDelta, RepositoryService repository,
boolean enforceReferentialIntegrity, boolean forceFilterReevaluation,
EvaluationTimeType resolutionTime, boolean throwExceptionOnFailure,
PrismContext prismContext, OperationResult result) {
Visitor visitor = visitable -> {
if (!(visitable instanceof PrismReferenceValue)) {
return;
}
resolveRef((PrismReferenceValue)visitable, repository, enforceReferentialIntegrity, forceFilterReevaluation,
resolutionTime, prismContext, objectDelta.toString(), throwExceptionOnFailure, result);
};
// We could use objectDelta.accept(visitor), but we want to visit only values to add and replace
// (NOT values to delete! - otherwise very strange effects could result)
// Another problem is that it is possible that one of valuesToAdd became (after resolving)
// a value that is meant do be deleted. The result would be deletion of that value; definitely
// not what we would want or expect. So we have to check whether a value that was not among
// values to be deleted accidentally becomes one of values to be deleted.
if (objectDelta.isAdd()) {
objectDelta.getObjectToAdd().accept(visitor);
} else if (objectDelta.isModify()) {
for (ItemDelta<?,?> delta : objectDelta.getModifications()) {
applyVisitorToValues(delta.getValuesToAdd(), delta, visitor);
applyVisitorToValues(delta.getValuesToReplace(), delta, visitor);
}
}
}
// see description in caller
private static void applyVisitorToValues(Collection<? extends PrismValue> values, ItemDelta<?,?> delta, Visitor visitor) {
Collection<? extends PrismValue> valuesToDelete = delta.getValuesToDelete();
if (valuesToDelete == null) {
valuesToDelete = new ArrayList<>(0); // just to simplify the code below
}
if (values != null) {
for (PrismValue pval : values) {
boolean isToBeDeleted = valuesToDelete.contains(pval);
pval.accept(visitor);
if (!isToBeDeleted && valuesToDelete.contains(pval)) {
// value becomes 'to be deleted' -> we remove it from toBeDeleted list
delta.removeValueToDelete(pval);
}
}
}
}
private static void resolveRef(PrismReferenceValue refVal, RepositoryService repository,
boolean enforceReferentialIntegrity, boolean forceFilterReevaluation, EvaluationTimeType evaluationTimeType,
PrismContext prismContext, String contextDesc, boolean throwExceptionOnFailure, OperationResult parentResult) {
String refName = refVal.getParent() != null ?
refVal.getParent().getElementName().toString() : "(unnamed)";
if ((refVal.getResolutionTime() != null && refVal.getResolutionTime() != evaluationTimeType) ||
(refVal.getResolutionTime() == null && evaluationTimeType != EvaluationTimeType.IMPORT)) {
LOGGER.trace("Skipping resolution of reference {} in {} because the resolutionTime is set to {}", refName, contextDesc, refVal.getResolutionTime());
return;
}
OperationResult result = parentResult.createMinorSubresult(OPERATION_RESOLVE_REFERENCE);
result.addContext(OperationResult.CONTEXT_ITEM, refName);
QName typeQName = null;
if (refVal.getTargetType() != null) {
typeQName = refVal.getTargetType();
}
if (typeQName == null) {
PrismReferenceDefinition definition = (PrismReferenceDefinition) refVal.getParent().getDefinition();
if (definition != null) {
typeQName = definition.getTargetTypeName();
}
}
Class<? extends ObjectType> type = ObjectType.class;
if (typeQName != null) {
type = prismContext.getSchemaRegistry().determineCompileTimeClass(typeQName);
if (type == null) {
result.recordWarning("Unknown type specified in reference or definition of reference " + refName + ": "
+ typeQName);
type = ObjectType.class;
}
}
SearchFilterType filter = refVal.getFilter();
if (!StringUtils.isBlank(refVal.getOid()) && (!forceFilterReevaluation || filter == null)) {
// We have OID (and "force filter reevaluation" is not requested or not possible)
if (filter != null) {
// We have both filter and OID. We will choose OID, but let's at
// least log a warning
LOGGER.debug("Both OID and filter for property {} in {}, OID takes precedence", refName, contextDesc);
}
// Nothing to resolve, but let's check if the OID exists
PrismObject<? extends ObjectType> object = null;
try {
object = repository.getObject(type, refVal.getOid(), null, result);
} catch (ObjectNotFoundException e) {
String message = "Reference " + refName + " refers to a non-existing object " + refVal.getOid();
if (enforceReferentialIntegrity) {
LOGGER.error(message);
result.recordFatalError(message);
if (throwExceptionOnFailure) {
throw new SystemException(message, e);
}
} else {
LOGGER.warn(message);
result.recordWarning(message);
}
} catch (SchemaException e) {
String message = "Schema error while trying to retrieve object " + refVal.getOid() + " : " + e.getMessage();
result.recordPartialError(message, e);
LOGGER.error(message, e);
// But continue otherwise
}
if (object != null && refVal.getOriginType() != null) {
// Check if declared and actual type matches
if (!object.getClass().equals(type)) {
result.recordWarning("Type mismatch on property " + refName + ": declared:"
+ refVal.getOriginType() + ", actual: " + object.getClass());
}
}
result.recordSuccessIfUnknown();
parentResult.computeStatus();
return;
}
if (filter == null) {
if (refVal.getObject() != null) {
LOGGER.trace("Skipping resolution of reference {} in {} because the object is present and the filter is not", refName, contextDesc);
result.recordNotApplicableIfUnknown();
return;
}
// No OID and no filter. We are lost.
String message = "Neither OID nor filter for property " + refName + ": cannot resolve reference";
result.recordFatalError(message);
if (throwExceptionOnFailure) {
throw new SystemException(message);
}
return;
}
// No OID and we have filter. Let's check the filter a bit
ObjectFilter objFilter;
try{
PrismObjectDefinition objDef = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(type);
objFilter = QueryConvertor.parseFilter(filter, objDef);
} catch (SchemaException ex){
LOGGER.error("Failed to convert object filter from filter because of: "+ ex.getMessage() + "; filter: " + filter.debugDump(), ex);
throw new SystemException("Failed to convert object filter from filter. Reason: " + ex.getMessage(), ex);
}
LOGGER.trace("Resolving using filter {}", objFilter.debugDump());
List<PrismObject<? extends ObjectType>> objects;
QName objectType = refVal.getTargetType();
if (objectType == null) {
String message = "Missing definition of type of reference " + refName;
result.recordFatalError(message);
if (throwExceptionOnFailure) {
throw new SystemException(message);
}
return;
}
if (containExpression(objFilter)){
result.recordSuccessIfUnknown();
return;
}
try {
ObjectQuery query = ObjectQuery.createObjectQuery(objFilter);
objects = (List)repository.searchObjects(type, query, null, result);
} catch (SchemaException e) {
// This is unexpected, but may happen. Record fatal error
String message = "Repository schema error during resolution of reference " + refName;
result.recordFatalError(message, e);
if (throwExceptionOnFailure) {
throw new SystemException(message, e);
}
return;
} catch (SystemException e) {
// We don't want this to tear down entire import.
String message = "Repository system error during resolution of reference " + refName;
result.recordFatalError(message, e);
if (throwExceptionOnFailure) {
throw new SystemException(message, e);
}
return;
}
if (objects.isEmpty()) {
String message = "Repository reference " + refName + " cannot be resolved: filter matches no object";
result.recordFatalError(message);
if (throwExceptionOnFailure) {
throw new SystemException(message);
}
return;
}
if (objects.size() > 1) {
String message = "Repository reference " + refName
+ " cannot be resolved: filter matches " + objects.size() + " objects";
result.recordFatalError(message);
if (throwExceptionOnFailure) {
throw new SystemException(message);
}
return;
}
// Bingo. We have exactly one object.
String oid = objects.get(0).getOid();
refVal.setOid(oid);
result.recordSuccessIfUnknown();
}
private static boolean containExpression(ObjectFilter filter){
if (filter == null){
return false;
}
if (filter instanceof InOidFilter && ((InOidFilter) filter).getExpression() != null) {
return true;
}
if (filter instanceof FullTextFilter && ((FullTextFilter) filter).getExpression() != null) {
return true;
}
if (filter instanceof ValueFilter && ((ValueFilter) filter).getExpression() != null) {
return true;
}
return false;
}
public static ObjectClassComplexTypeDefinition determineObjectClass(RefinedResourceSchema refinedSchema, Task task) throws SchemaException {
QName objectclass = null;
PrismProperty<QName> objectclassProperty = task.getExtensionProperty(ModelConstants.OBJECTCLASS_PROPERTY_NAME);
if (objectclassProperty != null) {
objectclass = objectclassProperty.getValue().getValue();
}
ShadowKindType kind = null;
PrismProperty<ShadowKindType> kindProperty = task.getExtensionProperty(ModelConstants.KIND_PROPERTY_NAME);
if (kindProperty != null) {
kind = kindProperty.getValue().getValue();
}
String intent = null;
PrismProperty<String> intentProperty = task.getExtensionProperty(ModelConstants.INTENT_PROPERTY_NAME);
if (intentProperty != null) {
intent = intentProperty.getValue().getValue();
}
return determineObjectClassInternal(refinedSchema, objectclass, kind, intent, task);
}
public static ObjectClassComplexTypeDefinition determineObjectClass(RefinedResourceSchema refinedSchema, PrismObject<ShadowType> shadow) throws SchemaException {
ShadowType s = shadow.asObjectable();
return determineObjectClassInternal(refinedSchema, s.getObjectClass(), s.getKind(), s.getIntent(), s);
}
private static ObjectClassComplexTypeDefinition determineObjectClassInternal(
RefinedResourceSchema refinedSchema, QName objectclass, ShadowKindType kind, String intent, Object source) throws SchemaException {
if (kind == null && intent == null && objectclass != null) {
// Return generic object class definition from resource schema. No kind/intent means that we want
// to process all kinds and intents in the object class.
ObjectClassComplexTypeDefinition objectClassDefinition = refinedSchema.findObjectClassDefinition(objectclass);
if (objectClassDefinition == null) {
throw new SchemaException("No object class "+objectclass+" in the schema for "+source);
}
return objectClassDefinition;
}
RefinedObjectClassDefinition refinedObjectClassDefinition;
if (kind != null) {
refinedObjectClassDefinition = refinedSchema.getRefinedDefinition(kind, intent);
LOGGER.trace("Determined refined object class {} by using kind={}, intent={}",
new Object[]{refinedObjectClassDefinition, kind, intent});
} else if (objectclass != null) {
refinedObjectClassDefinition = refinedSchema.getRefinedDefinition(objectclass);
LOGGER.trace("Determined refined object class {} by using objectClass={}",
new Object[]{refinedObjectClassDefinition, objectclass});
} else {
if (LOGGER.isTraceEnabled()) {
LOGGER.debug("No kind or objectclass specified in {}, assuming null object class", source);
}
refinedObjectClassDefinition = null;
}
return refinedObjectClassDefinition;
}
public static void encrypt(Collection<ObjectDelta<? extends ObjectType>> deltas, Protector protector, ModelExecuteOptions options,
OperationResult result) {
// Encrypt values even before we log anything. We want to avoid showing unencrypted values in the logfiles
if (!ModelExecuteOptions.isNoCrypt(options)) {
for(ObjectDelta<? extends ObjectType> delta: deltas) {
try {
CryptoUtil.encryptValues(protector, delta);
} catch (EncryptionException e) {
result.recordFatalError(e);
throw new SystemException(e.getMessage(), e);
}
}
}
}
public static void setRequestee(Task task, LensContext context) {
PrismObject<? extends ObjectType> object;
if (context != null && context.getFocusContext() != null
&& UserType.class.isAssignableFrom(context.getFocusContext().getObjectTypeClass())) {
object = context.getFocusContext().getObjectAny();
} else {
object = null;
}
setRequestee(task, object);
}
public static <F extends ObjectType> void setRequestee(Task task, LensFocusContext<F> context) {
setRequestee(task, context.getLensContext());
}
public static void setRequestee(Task task, PrismObject object) {
LOGGER.trace("setting requestee in {} to {}", task, object);
if (task != null) {
task.setRequesteeTransient(object);
}
}
public static void clearRequestee(Task task) {
setRequestee(task, (PrismObject) null);
}
public static boolean isDryRun(Task task) throws SchemaException {
Boolean dryRun = isDryRunInternal(task);
if (dryRun == null && task.isLightweightAsynchronousTask() && task.getParentForLightweightAsynchronousTask() != null) {
dryRun = isDryRunInternal(task.getParentForLightweightAsynchronousTask());
}
return dryRun != null ? dryRun : Boolean.FALSE;
}
private static Boolean isDryRunInternal(Task task) throws SchemaException{
Validate.notNull(task, "Task must not be null.");
if (task.getExtension() == null) {
return null;
}
PrismProperty<Boolean> item = task.getExtensionProperty(SchemaConstants.MODEL_EXTENSION_DRY_RUN);
if (item == null || item.isEmpty()) {
return null;
}
if (item.getValues().size() > 1) {
throw new SchemaException("Unexpected number of values for option 'dry run'.");
}
return item.getValues().iterator().next().getValue();
}
public static ModelExecuteOptions getModelExecuteOptions(Task task) throws SchemaException {
Validate.notNull(task, "Task must not be null.");
if (task.getExtension() == null) {
return null;
}
LOGGER.info("Task:\n{}",task.debugDump(1));
PrismProperty<ModelExecuteOptionsType> item = task.getExtensionProperty(SchemaConstants.C_MODEL_EXECUTE_OPTIONS);
if (item == null || item.isEmpty()) {
return null;
}
LOGGER.info("Item:\n{}",item.debugDump(1));
if (item.getValues().size() > 1) {
throw new SchemaException("Unexpected number of values for option 'modelExecuteOptions'.");
}
ModelExecuteOptionsType modelExecuteOptionsType = item.getValues().iterator().next().getValue();
if (modelExecuteOptionsType == null) {
return null;
}
LOGGER.info("modelExecuteOptionsType: {}",modelExecuteOptionsType);
ModelExecuteOptions modelExecuteOptions = ModelExecuteOptions.fromModelExecutionOptionsType(modelExecuteOptionsType);
LOGGER.info("modelExecuteOptions: {}",modelExecuteOptions);
return modelExecuteOptions;
}
public static ExpressionVariables getDefaultExpressionVariables(@NotNull LensContext<?> context, @Nullable LensProjectionContext projCtx) throws SchemaException {
ExpressionVariables variables = new ExpressionVariables();
if (context.getFocusContext() != null) {
variables.addVariableDefinition(ExpressionConstants.VAR_FOCUS, context.getFocusContext().getObjectDeltaObject());
variables.addVariableDefinition(ExpressionConstants.VAR_USER, context.getFocusContext().getObjectDeltaObject());
}
if (projCtx != null) {
variables.addVariableDefinition(ExpressionConstants.VAR_PROJECTION, projCtx.getObjectDeltaObject());
variables.addVariableDefinition(ExpressionConstants.VAR_SHADOW, projCtx.getObjectDeltaObject());
variables.addVariableDefinition(ExpressionConstants.VAR_ACCOUNT, projCtx.getObjectDeltaObject());
variables.addVariableDefinition(ExpressionConstants.VAR_RESOURCE, projCtx.getResource());
}
variables.addVariableDefinition(ExpressionConstants.VAR_OPERATION, projCtx.getOperation().getValue());
variables.addVariableDefinition(ExpressionConstants.VAR_ITERATION, LensUtil.getIterationVariableValue(projCtx));
variables.addVariableDefinition(ExpressionConstants.VAR_ITERATION_TOKEN, LensUtil.getIterationTokenVariableValue(projCtx));
variables.addVariableDefinition(ExpressionConstants.VAR_CONFIGURATION, context.getSystemConfiguration());
return variables;
}
public static ExpressionVariables getDefaultExpressionVariables(ObjectType focusType,
ShadowType shadowType, ResourceType resourceType, SystemConfigurationType configurationType) {
PrismObject<? extends ObjectType> focus = null;
if (focusType != null) {
focus = focusType.asPrismObject();
}
PrismObject<? extends ShadowType> shadow = null;
if (shadowType != null) {
shadow = shadowType.asPrismObject();
}
PrismObject<ResourceType> resource = null;
if (resourceType != null) {
resource = resourceType.asPrismObject();
}
PrismObject<SystemConfigurationType> configuration = null;
if (configurationType != null) {
configuration = configurationType.asPrismObject();
}
return getDefaultExpressionVariables(focus, shadow, null, resource, configuration, null);
}
public static <O extends ObjectType> ExpressionVariables getDefaultExpressionVariables(PrismObject<? extends ObjectType> focus,
PrismObject<? extends ShadowType> shadow, ResourceShadowDiscriminator discr,
PrismObject<ResourceType> resource, PrismObject<SystemConfigurationType> configuration, LensElementContext<O> affectedElementContext) {
ExpressionVariables variables = new ExpressionVariables();
addDefaultExpressionVariables(variables, focus, shadow, discr, resource, configuration, affectedElementContext);
return variables;
}
public static <O extends ObjectType> void addDefaultExpressionVariables(ExpressionVariables variables, PrismObject<? extends ObjectType> focus,
PrismObject<? extends ShadowType> shadow, ResourceShadowDiscriminator discr,
PrismObject<ResourceType> resource, PrismObject<SystemConfigurationType> configuration, LensElementContext<O> affectedElementContext) {
// Legacy. And convenience/understandability.
if (focus == null || focus.canRepresent(UserType.class) || (discr != null && discr.getKind() == ShadowKindType.ACCOUNT)) {
variables.addVariableDefinition(ExpressionConstants.VAR_USER, focus);
variables.addVariableDefinition(ExpressionConstants.VAR_ACCOUNT, shadow);
}
variables.addVariableDefinition(ExpressionConstants.VAR_FOCUS, focus);
variables.addVariableDefinition(ExpressionConstants.VAR_SHADOW, shadow);
variables.addVariableDefinition(ExpressionConstants.VAR_RESOURCE, resource);
variables.addVariableDefinition(ExpressionConstants.VAR_CONFIGURATION, configuration);
if (affectedElementContext != null) {
variables.addVariableDefinition(ExpressionConstants.VAR_OPERATION, affectedElementContext.getOperation().getValue());
}
}
public static void addAssignmentPathVariables(AssignmentPathVariables assignmentPathVariables, ExpressionVariables expressionVariables) {
if (assignmentPathVariables != null) {
expressionVariables.addVariableDefinition(ExpressionConstants.VAR_ASSIGNMENT, assignmentPathVariables.getMagicAssignment());
expressionVariables.addVariableDefinition(ExpressionConstants.VAR_ASSIGNMENT_PATH, assignmentPathVariables.getAssignmentPath());
expressionVariables.addVariableDefinition(ExpressionConstants.VAR_IMMEDIATE_ASSIGNMENT, assignmentPathVariables.getImmediateAssignment());
expressionVariables.addVariableDefinition(ExpressionConstants.VAR_THIS_ASSIGNMENT, assignmentPathVariables.getThisAssignment());
expressionVariables.addVariableDefinition(ExpressionConstants.VAR_FOCUS_ASSIGNMENT, assignmentPathVariables.getFocusAssignment());
expressionVariables.addVariableDefinition(ExpressionConstants.VAR_IMMEDIATE_ROLE, assignmentPathVariables.getImmediateRole());
} else {
// to avoid "no such variable" exceptions in boundary cases
// for null/empty paths we might consider creating empty AssignmentPathVariables objects to keep null/empty path distinction
expressionVariables.addVariableDefinition(ExpressionConstants.VAR_ASSIGNMENT_PATH, null);
}
}
public static String getPolicyDesc(ObjectSynchronizationType synchronizationPolicy) {
if (synchronizationPolicy == null) {
return null;
}
if (synchronizationPolicy.getName() != null) {
return synchronizationPolicy.getName();
}
return synchronizationPolicy.toString();
}
public static PrismReferenceValue determineAuditTargetDeltaOps(Collection<ObjectDeltaOperation<? extends ObjectType>> deltaOps) {
if (deltaOps == null || deltaOps.isEmpty()) {
return null;
}
if (deltaOps.size() == 1) {
ObjectDeltaOperation<? extends ObjectType> deltaOp = deltaOps.iterator().next();
return getAditTarget(deltaOp.getObjectDelta());
}
for (ObjectDeltaOperation<? extends ObjectType> deltaOp: deltaOps) {
if (!ShadowType.class.isAssignableFrom(deltaOp.getObjectDelta().getObjectTypeClass())) {
return getAditTarget(deltaOp.getObjectDelta());
}
}
// Several raw operations, all on shadows, no focus ... this should not happen
// But if it does we rather do not specify any target. We should not like to choose
// target randomly. That would be confusing.
return null;
}
public static PrismReferenceValue determineAuditTarget(Collection<ObjectDelta<? extends ObjectType>> deltas) {
if (deltas == null || deltas.isEmpty()) {
return null;
}
if (deltas.size() == 1) {
ObjectDelta<? extends ObjectType> delta = deltas.iterator().next();
return getAditTarget(delta);
}
for (ObjectDelta<? extends ObjectType> delta: deltas) {
if (!ShadowType.class.isAssignableFrom(delta.getObjectTypeClass())) {
return getAditTarget(delta);
}
}
// Several raw operations, all on shadows, no focus ... this should not happen
// But if it does we rather do not specify any target. We should not like to choose
// target randomly. That would be confusing.
return null;
}
public static PrismReferenceValue getAditTarget(ObjectDelta<? extends ObjectType> delta) {
PrismReferenceValue targetRef = new PrismReferenceValue(delta.getOid());
targetRef.setTargetType(ObjectTypes.getObjectType(delta.getObjectTypeClass()).getTypeQName());
if (delta.isAdd()) {
targetRef.setObject(delta.getObjectToAdd());
}
return targetRef;
}
public static <V extends PrismValue, F extends ObjectType> List<V> evaluateScript(
ScriptExpression scriptExpression, LensContext<F> lensContext, ExpressionVariables variables, boolean useNew, String shortDesc, Task task, OperationResult parentResult) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException {
ExpressionEnvironment<F> env = new ExpressionEnvironment<>();
env.setLensContext(lensContext);
env.setCurrentResult(parentResult);
env.setCurrentTask(task);
ModelExpressionThreadLocalHolder.pushExpressionEnvironment(env);
try {
return scriptExpression.evaluate(variables, ScriptExpressionReturnTypeType.SCALAR, useNew, shortDesc, task, parentResult);
} finally {
ModelExpressionThreadLocalHolder.popExpressionEnvironment();
// if (lensContext.getDebugListener() != null) {
// lensContext.getDebugListener().afterScriptEvaluation(lensContext, scriptExpression);
// }
}
}
}