/*
* 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.common.mapping;
import static org.testng.AssertJUnit.assertEquals;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;
import org.xml.sax.SAXException;
import com.evolveum.midpoint.model.common.expression.ExpressionFactory;
import com.evolveum.midpoint.model.common.expression.ExpressionTestUtil;
import com.evolveum.midpoint.model.common.expression.ObjectDeltaObject;
import com.evolveum.midpoint.model.common.expression.Source;
import com.evolveum.midpoint.model.common.expression.StringPolicyResolver;
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.OriginType;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismObjectDefinition;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.crypto.ProtectorImpl;
import com.evolveum.midpoint.prism.crypto.EncryptionException;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.util.PrismTestUtil;
import com.evolveum.midpoint.schema.MidPointPrismContextFactory;
import com.evolveum.midpoint.schema.constants.ExpressionConstants;
import com.evolveum.midpoint.schema.constants.MidPointConstants;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectResolver;
import com.evolveum.midpoint.test.util.DirectoryFileObjectResolver;
import com.evolveum.midpoint.test.util.MidPointTestConstants;
import com.evolveum.midpoint.test.util.TestUtil;
import com.evolveum.midpoint.util.PrettyPrinter;
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.xml.ns._public.common.common_3.MappingType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.StringPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType;
/**
* The class that takes care of all the ornaments of value construction execution. It is used to make the
* tests easy to write.
*
* @author Radovan Semancik
*
*/
public class MappingTestEvaluator {
public static File TEST_DIR = new File(MidPointTestConstants.TEST_RESOURCES_DIR, "mapping");
public static final File USER_OLD_FILE = new File(TEST_DIR, "user-jack.xml");
public static final File ACCOUNT_FILE = new File(TEST_DIR, "account-jack.xml");
public static final String USER_OLD_OID = "2f9b9299-6f45-498f-bc8e-8d17c6b93b20";
private static final File PASSWORD_POLICY_FILE = new File(TEST_DIR, "password-policy.xml");
private PrismContext prismContext;
private MappingFactory mappingFactory;
ProtectorImpl protector;
public PrismContext getPrismContext() {
return prismContext;
}
public void init() throws SchemaException, SAXException, IOException {
PrettyPrinter.setDefaultNamespacePrefix(MidPointConstants.NS_MIDPOINT_PUBLIC_PREFIX);
PrismTestUtil.resetPrismContext(MidPointPrismContextFactory.FACTORY);
prismContext = PrismTestUtil.createInitializedPrismContext();
ObjectResolver resolver = new DirectoryFileObjectResolver(MidPointTestConstants.OBJECTS_DIR);
protector = ExpressionTestUtil.createInitializedProtector(prismContext);
ExpressionFactory expressionFactory = ExpressionTestUtil.createInitializedExpressionFactory(resolver, protector, prismContext, null);
mappingFactory = new MappingFactory();
mappingFactory.setExpressionFactory(expressionFactory);
mappingFactory.setObjectResolver(resolver);
mappingFactory.setPrismContext(prismContext);
mappingFactory.setProfiling(true);
mappingFactory.setProtector(protector);
}
public ProtectorImpl getProtector() {
return protector;
}
public <T> Mapping<PrismPropertyValue<T>, PrismPropertyDefinition<T>> createMapping(String filename, String testName, final StringPolicyType policy, String defaultTargetPropertyName, ObjectDelta<UserType> userDelta) throws SchemaException, IOException, JAXBException, EncryptionException {
return this.<T>createMappingBuilder(filename, testName, policy, toPath(defaultTargetPropertyName), userDelta).build();
}
public <T> Mapping<PrismPropertyValue<T>, PrismPropertyDefinition<T>> createMapping(String filename, String testName, String defaultTargetPropertyName,
ObjectDelta<UserType> userDelta) throws SchemaException, IOException, JAXBException, EncryptionException {
return this.<T>createMappingBuilder(filename, testName, null, toPath(defaultTargetPropertyName), userDelta).build();
}
public <T> Mapping.Builder<PrismPropertyValue<T>, PrismPropertyDefinition<T>> createMappingBuilder(String filename, String testName, String defaultTargetPropertyName,
ObjectDelta<UserType> userDelta) throws SchemaException, IOException, JAXBException, EncryptionException {
return createMappingBuilder(filename, testName, null, toPath(defaultTargetPropertyName), userDelta);
}
public <T> Mapping<PrismPropertyValue<T>, PrismPropertyDefinition<T>> createMapping(String filename, String testName, QName defaultTargetPropertyName,
ObjectDelta<UserType> userDelta) throws SchemaException, IOException, JAXBException, EncryptionException {
return this.<T>createMappingBuilder(filename, testName, null, toPath(defaultTargetPropertyName), userDelta).build();
}
public <T> Mapping<PrismPropertyValue<T>, PrismPropertyDefinition<T>> createMapping(String filename, String testName, String defaultTargetPropertyName,
ObjectDelta<UserType> userDelta, PrismObject<UserType> userOld) throws SchemaException, IOException, JAXBException {
return this.<T>createMappingBuilder(filename, testName, null, toPath(defaultTargetPropertyName), userDelta, userOld).build();
}
public <T> Mapping.Builder<PrismPropertyValue<T>, PrismPropertyDefinition<T>> createMappingBuilder(String filename, String testName, String defaultTargetPropertyName,
ObjectDelta<UserType> userDelta, PrismObject<UserType> userOld) throws SchemaException, IOException, JAXBException {
return this.createMappingBuilder(filename, testName, null, toPath(defaultTargetPropertyName), userDelta, userOld);
}
public <T> Mapping<PrismPropertyValue<T>, PrismPropertyDefinition<T>> createMapping(String filename, String testName, ItemPath defaultTargetPropertyName, ObjectDelta<UserType> userDelta) throws SchemaException, IOException, JAXBException, EncryptionException {
return this.<T>createMappingBuilder(filename, testName, null, defaultTargetPropertyName, userDelta).build();
}
public <T> Mapping.Builder<PrismPropertyValue<T>, PrismPropertyDefinition<T>> createMappingBuilder(String filename, String testName, final StringPolicyType policy,
ItemPath defaultTargetPropertyPath, ObjectDelta<UserType> userDelta)
throws SchemaException, IOException, JAXBException, EncryptionException {
PrismObject<UserType> userOld = null;
if (userDelta == null || !userDelta.isAdd()) {
userOld = getUserOld();
}
return createMappingBuilder(filename, testName, policy, defaultTargetPropertyPath, userDelta, userOld);
}
public <T> Mapping.Builder<PrismPropertyValue<T>, PrismPropertyDefinition<T>> createMappingBuilder(String filename, String testName, final StringPolicyType policy,
ItemPath defaultTargetPropertyPath, ObjectDelta<UserType> userDelta, PrismObject<UserType> userOld)
throws SchemaException, IOException, JAXBException {
MappingType mappingType = PrismTestUtil.parseAtomicValue(
new File(TEST_DIR, filename), MappingType.COMPLEX_TYPE);
Mapping.Builder<PrismPropertyValue<T>,PrismPropertyDefinition<T>> mappingBuilder = mappingFactory.createMappingBuilder(mappingType, testName);
// Source context: user
ObjectDeltaObject<UserType> userOdo = new ObjectDeltaObject<>(userOld, userDelta, null);
userOdo.recompute();
mappingBuilder.setSourceContext(userOdo);
// Variable $user
mappingBuilder.addVariableDefinition(ExpressionConstants.VAR_USER, userOdo);
// Variable $account
PrismObject<ShadowType> account = getAccount();
ObjectDeltaObject<ShadowType> accountOdo = new ObjectDeltaObject<ShadowType>(account , null, null);
accountOdo.recompute();
mappingBuilder.addVariableDefinition(ExpressionConstants.VAR_ACCOUNT, accountOdo);
// Target context: user
PrismObjectDefinition<UserType> userDefinition = getUserDefinition();
mappingBuilder.setTargetContext(userDefinition);
StringPolicyResolver stringPolicyResolver = new StringPolicyResolver() {
ItemPath outputPath;
ItemDefinition outputDefinition;
@Override
public void setOutputPath(ItemPath outputPath) {
this.outputPath = outputPath;
}
@Override
public void setOutputDefinition(ItemDefinition outputDefinition) {
this.outputDefinition = outputDefinition;
}
@Override
public StringPolicyType resolve() {
return policy;
}
};
mappingBuilder.setStringPolicyResolver(stringPolicyResolver);
// Default target
if (defaultTargetPropertyPath != null) {
PrismPropertyDefinition<T> targetDefDefinition = userDefinition.findItemDefinition(defaultTargetPropertyPath);
if (targetDefDefinition == null) {
throw new IllegalArgumentException("The item path '"+defaultTargetPropertyPath+"' does not have a definition in "+userDefinition);
}
mappingBuilder.setDefaultTargetDefinition(targetDefDefinition);
}
return mappingBuilder;
}
public <T> Mapping<PrismPropertyValue<T>, PrismPropertyDefinition<T>> createInboudMapping(String filename, String testName, ItemDelta delta, UserType user, ShadowType account, ResourceType resource, final StringPolicyType policy) throws SchemaException, IOException, JAXBException{
MappingType mappingType = PrismTestUtil.parseAtomicValue(
new File(TEST_DIR, filename), MappingType.COMPLEX_TYPE);
Mapping.Builder<PrismPropertyValue<T>,PrismPropertyDefinition<T>> builder = mappingFactory.createMappingBuilder(mappingType, testName);
Source<PrismPropertyValue<T>,PrismPropertyDefinition<T>> defaultSource = new Source<>(null, delta, null, ExpressionConstants.VAR_INPUT);
defaultSource.recompute();
builder.setDefaultSource(defaultSource);
builder.setTargetContext(getUserDefinition());
builder.addVariableDefinition(ExpressionConstants.VAR_USER, user);
builder.addVariableDefinition(ExpressionConstants.VAR_FOCUS, user);
builder.addVariableDefinition(ExpressionConstants.VAR_ACCOUNT, account.asPrismObject());
builder.addVariableDefinition(ExpressionConstants.VAR_SHADOW, account.asPrismObject());
StringPolicyResolver stringPolicyResolver = new StringPolicyResolver() {
ItemPath outputPath;
ItemDefinition outputDefinition;
@Override
public void setOutputPath(ItemPath outputPath) {
this.outputPath = outputPath;
}
@Override
public void setOutputDefinition(ItemDefinition outputDefinition) {
this.outputDefinition = outputDefinition;
}
@Override
public StringPolicyType resolve() {
return policy;
}
};
builder.setStringPolicyResolver(stringPolicyResolver);
builder.setOriginType(OriginType.INBOUND);
builder.setOriginObject(resource);
return builder.build();
}
protected PrismObject<UserType> getUserOld() throws SchemaException, EncryptionException, IOException {
PrismObject<UserType> user = PrismTestUtil.parseObject(USER_OLD_FILE);
ProtectedStringType passwordPs = user.asObjectable().getCredentials().getPassword().getValue();
protector.encrypt(passwordPs);
return user;
}
protected PrismObject<ShadowType> getAccount() throws SchemaException, IOException {
return PrismTestUtil.parseObject(ACCOUNT_FILE);
}
public PrismObjectDefinition<UserType> getUserDefinition() {
return prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(UserType.class);
}
public <T,I> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateMapping(String filename, String testName,
ItemPath defaultTargetPropertyPath)
throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException, EncryptionException {
Mapping<PrismPropertyValue<T>,PrismPropertyDefinition<T>> mapping = createMapping(filename, testName, defaultTargetPropertyPath, null);
OperationResult opResult = new OperationResult(testName);
mapping.evaluate(null, opResult);
assertResult(opResult);
PrismValueDeltaSetTriple<PrismPropertyValue<T>> outputTriple = mapping.getOutputTriple();
if (outputTriple != null) {
outputTriple.checkConsistence();
}
return outputTriple;
}
public <T,I> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateMapping(String filename, String testName,
QName defaultTargetPropertyName)
throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException, EncryptionException {
Mapping<PrismPropertyValue<T>,PrismPropertyDefinition<T>> mapping = createMapping(filename, testName, defaultTargetPropertyName, null);
OperationResult opResult = new OperationResult(testName);
mapping.evaluate(null, opResult);
assertResult(opResult);
PrismValueDeltaSetTriple<PrismPropertyValue<T>> outputTriple = mapping.getOutputTriple();
if (outputTriple != null) {
outputTriple.checkConsistence();
}
return outputTriple;
}
public <T,I> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateMapping(String filename, String testName,
String defaultTargetPropertyName)
throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException, EncryptionException {
Mapping<PrismPropertyValue<T>,PrismPropertyDefinition<T>> mapping = createMapping(filename, testName, defaultTargetPropertyName, null);
OperationResult opResult = new OperationResult(testName);
mapping.evaluate(null, opResult);
assertResult(opResult);
PrismValueDeltaSetTriple<PrismPropertyValue<T>> outputTriple = mapping.getOutputTriple();
if (outputTriple != null) {
outputTriple.checkConsistence();
}
return outputTriple;
}
public void assertResult(OperationResult opResult) {
if (opResult.isEmpty()) {
// this is OK. Nothing added to result.
return;
}
opResult.computeStatus();
TestUtil.assertSuccess(opResult);
}
public <T,I> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateMappingDynamicAdd(String filename, String testName,
String defaultTargetPropertyName,
String changedPropertyName, I... valuesToAdd) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException, EncryptionException {
return evaluateMappingDynamicAdd(filename, testName, toPath(defaultTargetPropertyName), changedPropertyName, valuesToAdd);
}
public <T,I> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateMappingDynamicAdd(String filename, String testName,
ItemPath defaultTargetPropertyPath,
String changedPropertyName, I... valuesToAdd) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException, EncryptionException {
ObjectDelta<UserType> userDelta = ObjectDelta.createModificationAddProperty(UserType.class, USER_OLD_OID, toPath(changedPropertyName),
prismContext, valuesToAdd);
Mapping<PrismPropertyValue<T>,PrismPropertyDefinition<T>> mapping = createMapping(filename, testName, defaultTargetPropertyPath, userDelta);
OperationResult opResult = new OperationResult(testName);
mapping.evaluate(null, opResult);
assertResult(opResult);
PrismValueDeltaSetTriple<PrismPropertyValue<T>> outputTriple = mapping.getOutputTriple();
if (outputTriple != null) {
outputTriple.checkConsistence();
}
return outputTriple;
}
public <T,I> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateMappingDynamicDelete(String filename, String testName,
String defaultTargetPropertyName,
String changedPropertyName, I... valuesToAdd) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException, EncryptionException {
ObjectDelta<UserType> userDelta = ObjectDelta.createModificationDeleteProperty(UserType.class, USER_OLD_OID, toPath(changedPropertyName),
prismContext, valuesToAdd);
Mapping<PrismPropertyValue<T>,PrismPropertyDefinition<T>> mapping = createMapping(filename, testName, defaultTargetPropertyName, userDelta);
OperationResult opResult = new OperationResult(testName);
mapping.evaluate(null, opResult);
assertResult(opResult);
PrismValueDeltaSetTriple<PrismPropertyValue<T>> outputTriple = mapping.getOutputTriple();
if (outputTriple != null) {
outputTriple.checkConsistence();
}
return outputTriple;
}
public <T,I> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateMappingDynamicReplace(String filename, String testName,
String defaultTargetPropertyName,
String changedPropertyName, I... valuesToReplace) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException, EncryptionException {
ObjectDelta<UserType> userDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, USER_OLD_OID, toPath(changedPropertyName),
prismContext, valuesToReplace);
Mapping<PrismPropertyValue<T>,PrismPropertyDefinition<T>> mapping = createMapping(filename, testName, defaultTargetPropertyName, userDelta);
OperationResult opResult = new OperationResult(testName);
mapping.evaluate(null, opResult);
assertResult(opResult);
PrismValueDeltaSetTriple<PrismPropertyValue<T>> outputTriple = mapping.getOutputTriple();
if (outputTriple != null) {
outputTriple.checkConsistence();
}
return outputTriple;
}
public <T,I> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateMappingDynamicReplace(String filename, String testName,
String defaultTargetPropertyName,
ItemPath changedPropertyName, I... valuesToReplace) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException, EncryptionException {
ObjectDelta<UserType> userDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, USER_OLD_OID, changedPropertyName,
prismContext, valuesToReplace);
Mapping<PrismPropertyValue<T>,PrismPropertyDefinition<T>> mapping = createMapping(filename, testName, defaultTargetPropertyName, userDelta);
OperationResult opResult = new OperationResult(testName);
mapping.evaluate(null, opResult);
assertResult(opResult);
PrismValueDeltaSetTriple<PrismPropertyValue<T>> outputTriple = mapping.getOutputTriple();
if (outputTriple != null) {
outputTriple.checkConsistence();
}
return outputTriple;
}
public <T,I> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateMappingDynamicReplace(String filename, String testName,
ItemPath defaultTargetPropertyName,
String changedPropertyName, I... valuesToReplace) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException, EncryptionException {
ObjectDelta<UserType> userDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, USER_OLD_OID, toPath(changedPropertyName),
prismContext, valuesToReplace);
Mapping<PrismPropertyValue<T>,PrismPropertyDefinition<T>> mapping = createMapping(filename, testName, defaultTargetPropertyName, userDelta);
OperationResult opResult = new OperationResult(testName);
mapping.evaluate(null, opResult);
assertResult(opResult);
PrismValueDeltaSetTriple<PrismPropertyValue<T>> outputTriple = mapping.getOutputTriple();
if (outputTriple != null) {
outputTriple.checkConsistence();
}
return outputTriple;
}
public <T,I> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateMappingDynamicReplace(String filename, String testName,
ItemPath defaultTargetPropertyName,
ItemPath changedPropertyName, I... valuesToReplace) throws SchemaException, IOException, JAXBException, ExpressionEvaluationException, ObjectNotFoundException, EncryptionException {
ObjectDelta<UserType> userDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, USER_OLD_OID, changedPropertyName,
prismContext, valuesToReplace);
Mapping<PrismPropertyValue<T>,PrismPropertyDefinition<T>> mapping = createMapping(filename, testName, defaultTargetPropertyName, userDelta);
OperationResult opResult = new OperationResult(testName);
mapping.evaluate(null, opResult);
assertResult(opResult);
PrismValueDeltaSetTriple<PrismPropertyValue<T>> outputTriple = mapping.getOutputTriple();
if (outputTriple != null) {
outputTriple.checkConsistence();
}
return outputTriple;
}
public ItemPath toPath(String propertyName) {
return new ItemPath(new QName(SchemaConstants.NS_C, propertyName));
}
public ItemPath toPath(QName propertyName) {
return new ItemPath(propertyName);
}
public static <T> T getSingleValue(String setName, Collection<PrismPropertyValue<T>> set) {
assertEquals("Expected single value in "+setName+" but found "+set.size()+" values: "+set, 1, set.size());
PrismPropertyValue<T> propertyValue = set.iterator().next();
return propertyValue.getValue();
}
public StringPolicyType getStringPolicy() throws SchemaException, IOException {
PrismObject<ValuePolicyType> passwordPolicy = PrismTestUtil.parseObject(PASSWORD_POLICY_FILE);
return passwordPolicy.asObjectable().getStringPolicy();
}
public Object createProtectedString(String string) throws EncryptionException {
return protector.encryptString(string);
}
public void assertProtectedString(String desc,
Collection<PrismPropertyValue<ProtectedStringType>> set,
String expected) throws EncryptionException {
assertEquals("Unexpected size of "+desc+": "+set, 1, set.size());
PrismPropertyValue<ProtectedStringType> pval = set.iterator().next();
ProtectedStringType ps = pval.getValue();
String zeroString = protector.decryptString(ps);
assertEquals("Unexpected value in "+desc+": "+set, expected, zeroString);
}
}