/*
* Copyright (c) 2010-2017 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.schema.parser;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.lex.dom.DomLexicalProcessor;
import com.evolveum.midpoint.prism.marshaller.QueryConvertor;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.NameItemPathSegment;
import com.evolveum.midpoint.prism.query.EqualFilter;
import com.evolveum.midpoint.prism.query.ExpressionWrapper;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.util.ItemPathUtil;
import com.evolveum.midpoint.prism.util.PrismAsserts;
import com.evolveum.midpoint.prism.util.PrismTestUtil;
import com.evolveum.midpoint.prism.xnode.MapXNode;
import com.evolveum.midpoint.prism.xnode.RootXNode;
import com.evolveum.midpoint.schema.SchemaConstantsGenerated;
import com.evolveum.midpoint.schema.TestConstants;
import com.evolveum.midpoint.schema.constants.MidPointConstants;
import com.evolveum.midpoint.schema.processor.ResourceSchema;
import com.evolveum.midpoint.schema.processor.ResourceSchemaImpl;
import com.evolveum.midpoint.schema.util.ResourceTypeUtil;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.prism.xml.ns._public.query_3.SearchFilterType;
import com.evolveum.prism.xml.ns._public.types_3.*;
import org.testng.AssertJUnit;
import org.testng.annotations.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import java.io.File;
import java.util.List;
import static com.evolveum.midpoint.schema.TestConstants.RESOURCE_FILE_BASENAME;
import static com.evolveum.midpoint.schema.TestConstants.RESOURCE_FILE_SIMPLE_BASENAME;
import static com.evolveum.midpoint.schema.util.SchemaTestConstants.ICFC_CONFIGURATION_PROPERTIES;
import static org.testng.AssertJUnit.*;
/**
* @author semancik
*
*/
public class TestParseResource extends AbstractContainerValueParserTest<ResourceType> {
@Override
protected File getFile() {
return getFile(RESOURCE_FILE_BASENAME);
}
@Test
public void testParseResourceFile() throws Exception {
displayTestTitle("testParseResourceFile");
// GIVEN
PrismContext prismContext = getPrismContext();
// WHEN
PrismObject<ResourceType> resource = prismContext.parseObject(getFile(RESOURCE_FILE_BASENAME));
// THEN
System.out.println("Parsed resource:");
System.out.println(resource.debugDump());
assertResource(resource, true, true, false);
}
@Test
public void testParseResourceFileSimple() throws Exception {
displayTestTitle("testParseResourceFileSimple");
// GIVEN
PrismContext prismContext = getPrismContext();
// WHEN
PrismObject<ResourceType> resource = prismContext.parseObject(getFile(RESOURCE_FILE_SIMPLE_BASENAME));
// THEN
System.out.println("Parsed resource:");
System.out.println(resource.debugDump());
assertResource(resource, true, true, true);
}
@Test
public void testParseResourceRoundtrip() throws Exception {
displayTestTitle("testParseResourceRoundtrip");
// GIVEN
PrismContext prismContext = getPrismContext();
PrismObject<ResourceType> resource = prismContext.parseObject(getFile(RESOURCE_FILE_BASENAME));
System.out.println("Parsed resource:");
System.out.println(resource.debugDump());
assertResource(resource, true, false, false);
// SERIALIZE
String serializedResource = prismContext.serializerFor(language).serialize(resource);
System.out.println("serialized resource:");
System.out.println(serializedResource);
// hack ... to make sure there's no "<clazz>" element there
assertFalse("<clazz> element is present in the serialized form!", serializedResource.contains("<clazz>"));
// RE-PARSE
PrismObject<ResourceType> reparsedResource = prismContext.parseObject(serializedResource);
System.out.println("Re-parsed resource:");
System.out.println(reparsedResource.debugDump());
// Cannot assert here. It will cause parsing of some of the raw values and diff will fail
assertResource(reparsedResource, true, false, false);
PrismProperty<SchemaDefinitionType> definitionProperty = reparsedResource.findContainer(ResourceType.F_SCHEMA).findProperty(XmlSchemaType.F_DEFINITION);
SchemaDefinitionType definitionElement = definitionProperty.getValue().getValue();
System.out.println("Re-parsed definition element:");
System.out.println(DOMUtil.serializeDOMToString(definitionElement.getSchema()));
ObjectDelta<ResourceType> objectDelta = resource.diff(reparsedResource);
System.out.println("Delta:");
System.out.println(objectDelta.debugDump());
assertTrue("Delta is not empty", objectDelta.isEmpty());
PrismAsserts.assertEquivalent("Resource re-parsed equivalence", resource, reparsedResource);
// // Compare schema container
//
// PrismContainer<?> originalSchemaContainer = resource.findContainer(ResourceType.F_SCHEMA);
// PrismContainer<?> reparsedSchemaContainer = reparsedResource.findContainer(ResourceType.F_SCHEMA);
}
/**
* Serialize and parse "schema" element on its own. There may be problems e.g. with preservation
* of namespace definitions.
*/
@Test
public void testSchemaRoundtrip() throws Exception {
displayTestTitle("testSchemaRoundtrip");
// GIVEN
PrismContext prismContext = getPrismContext();
PrismObject<ResourceType> resource = prismContext.parseObject(getFile(RESOURCE_FILE_BASENAME));
assertResource(resource, true, false, false);
PrismContainer<Containerable> schemaContainer = resource.findContainer(ResourceType.F_SCHEMA);
System.out.println("Parsed schema:");
System.out.println(schemaContainer.debugDump());
// SERIALIZE
String serializesSchema = prismContext.serializerFor(language).serialize(schemaContainer.getValue(), new QName("fakeNs", "fake"));
System.out.println("serialized schema:");
System.out.println(serializesSchema);
// RE-PARSE
PrismContainer reparsedSchemaContainer = (PrismContainer) prismContext.parserFor(serializesSchema).language(language).definition(schemaContainer.getDefinition()).parseItem();
System.out.println("Re-parsed schema container:");
System.out.println(reparsedSchemaContainer.debugDump());
// String reserializesSchema = prismContext.serializeContainerValueToString(reparsedSchemaContainer.getValue(), new QName("fakeNs", "fake"), PrismContext.LANG_XML);
//
// System.out.println("re-serialized schema:");
// System.out.println(reserializesSchema);
// Document reparsedDocument = DOMUtil.parseDocument(serializesSchema);
// Element reparsedSchemaElement = DOMUtil.getFirstChildElement(DOMUtil.getFirstChildElement(reparsedDocument));
// Element reparsedXsdSchemaElement = DOMUtil.getChildElement(DOMUtil.getFirstChildElement(reparsedSchemaElement), DOMUtil.XSD_SCHEMA_ELEMENT);
XmlSchemaType defType = (XmlSchemaType) reparsedSchemaContainer.getValue().asContainerable();
Element reparsedXsdSchemaElement = defType.getDefinition().getSchema();
ResourceSchema reparsedSchema = ResourceSchemaImpl.parse(reparsedXsdSchemaElement, "reparsed schema", prismContext);
}
@Override
protected void assertPrismContainerValueLocal(PrismContainerValue<ResourceType> value) throws SchemaException {
//assertResource(object.asContainerable().asPrismObject(), true, true);
}
protected void assertResource(PrismObject<ResourceType> resource, boolean checkConsistence, boolean checkJaxb, boolean isSimple)
throws SchemaException, JAXBException {
if (checkConsistence) {
resource.checkConsistence();
}
assertResourcePrism(resource, isSimple);
assertResourceJaxb(resource.asObjectable(), isSimple);
if (checkJaxb) {
// serializeDom(resource);
//serializeJaxb(resource);
}
}
private void assertResourcePrism(PrismObject<ResourceType> resource, boolean isSimple) throws SchemaException {
PrismContext prismContext = getPrismContext();
AssertJUnit.assertEquals("Wrong oid (prism)", TestConstants.RESOURCE_OID, resource.getOid());
// assertEquals("Wrong version", "42", resource.getVersion());
PrismObjectDefinition<ResourceType> resourceDefinition = resource.getDefinition();
assertNotNull("No resource definition", resourceDefinition);
PrismAsserts.assertObjectDefinition(resourceDefinition, new QName(SchemaConstantsGenerated.NS_COMMON, "resource"),
ResourceType.COMPLEX_TYPE, ResourceType.class);
assertEquals("Wrong class in resource", ResourceType.class, resource.getCompileTimeClass());
ResourceType resourceType = resource.asObjectable();
assertNotNull("asObjectable resulted in null", resourceType);
assertPropertyValue(resource, "name", PrismTestUtil.createPolyString("Embedded Test OpenDJ"));
assertPropertyDefinition(resource, "name", PolyStringType.COMPLEX_TYPE, 0, 1);
if (!isSimple) {
assertPropertyValue(resource, "namespace", TestConstants.RESOURCE_NAMESPACE);
assertPropertyDefinition(resource, "namespace", DOMUtil.XSD_ANYURI, 0, 1);
}
PrismReference connectorRef = resource.findReference(ResourceType.F_CONNECTOR_REF);
assertNotNull("No connectorRef", connectorRef);
PrismReferenceValue connectorRefVal = connectorRef.getValue();
assertNotNull("No connectorRef value", connectorRefVal);
assertEquals("Wrong type in connectorRef value", ConnectorType.COMPLEX_TYPE, connectorRefVal.getTargetType());
SearchFilterType filter = connectorRefVal.getFilter();
assertNotNull("No filter in connectorRef value", filter);
if (!isSimple) {
ObjectFilter objectFilter = QueryConvertor.parseFilter(filter, ConnectorType.class, prismContext);
assertTrue("Wrong kind of filter: " + objectFilter, objectFilter instanceof EqualFilter);
EqualFilter equalFilter = (EqualFilter) objectFilter;
ItemPath path = equalFilter.getPath(); // should be extension/x:extConnType
PrismAsserts.assertPathEqualsExceptForPrefixes("Wrong filter path",
namespaces ?
new ItemPath(new QName("extension"), new QName("http://x/", "extConnType")) :
new ItemPath(new QName("extension"), new QName("extConnType")),
path);
PrismPropertyValue filterValue = (PrismPropertyValue) equalFilter.getValues().get(0);
assertEquals("Wrong filter value", "org.identityconnectors.ldap.LdapConnector", ((RawType) filterValue.getValue()).getParsedRealValue(String.class).trim());
//assertEquals("Wrong filter value", "org.identityconnectors.ldap.LdapConnector", ((String) filterValue.getValue()).trim());
}
EvaluationTimeType resolutionTime = connectorRefVal.getResolutionTime();
if (isSimple) {
assertEquals("Wrong resolution time in connectorRef value", EvaluationTimeType.RUN, resolutionTime);
} else {
assertEquals("Wrong resolution time in connectorRef value", EvaluationTimeType.IMPORT, resolutionTime);
}
PrismContainer<?> configurationContainer = resource.findContainer(ResourceType.F_CONNECTOR_CONFIGURATION);
assertContainerDefinition(configurationContainer, "configuration", ConnectorConfigurationType.COMPLEX_TYPE, 1, 1);
PrismContainerValue<?> configContainerValue = configurationContainer.getValue();
List<Item<?,?>> configItems = configContainerValue.getItems();
assertEquals("Wrong number of config items", isSimple ? 1 : 4, configItems.size());
PrismContainer<?> ldapConfigPropertiesContainer = configurationContainer.findContainer(ICFC_CONFIGURATION_PROPERTIES);
assertNotNull("No icfcldap:configurationProperties container", ldapConfigPropertiesContainer);
PrismContainerDefinition<?> ldapConfigPropertiesContainerDef = ldapConfigPropertiesContainer.getDefinition();
assertNotNull("No icfcldap:configurationProperties container definition", ldapConfigPropertiesContainerDef);
assertEquals("icfcldap:configurationProperties container definition maxOccurs", 1, ldapConfigPropertiesContainerDef.getMaxOccurs());
List<Item<?,?>> ldapConfigPropItems = ldapConfigPropertiesContainer.getValue().getItems();
assertEquals("Wrong number of ldapConfigPropItems items", 7, ldapConfigPropItems.size());
PrismContainer<Containerable> schemaContainer = resource.findContainer(ResourceType.F_SCHEMA);
if (isSimple) {
assertNull("Schema sneaked in", schemaContainer);
} else {
assertNotNull("No schema container", schemaContainer);
}
PrismContainer<?> schemaHandlingContainer = resource.findContainer(ResourceType.F_SCHEMA_HANDLING);
if (isSimple) {
assertNull("SchemaHandling sneaked in", schemaHandlingContainer);
} else {
assertNotNull("No schemaHandling container", schemaHandlingContainer);
}
if (!isSimple) {
PrismProperty<SynchronizationType> synchronizationProp = resource.findProperty(ResourceType.F_SYNCHRONIZATION);
SynchronizationType synchronizationType = synchronizationProp.getRealValue();
ObjectSynchronizationType objectSynchronizationType = synchronizationType.getObjectSynchronization().get(0);
List<ConditionalSearchFilterType> correlations = objectSynchronizationType.getCorrelation();
assertEquals("Wrong number of correlation expressions", 1, correlations.size());
ConditionalSearchFilterType correlationFilterType = correlations.get(0);
System.out.println("\nCorrelation filter");
System.out.println(correlationFilterType.debugDump());
ObjectFilter objectFilter = QueryConvertor.parseFilter(correlationFilterType.serializeToXNode(), prismContext);
PrismAsserts.assertAssignableFrom(EqualFilter.class, objectFilter);
EqualFilter equalsFilter = (EqualFilter)objectFilter;
equalsFilter.getFullPath();
assertNull("Unexpected values in correlation expression", equalsFilter.getValues());
ExpressionWrapper expression = equalsFilter.getExpression();
assertNotNull("No expressions in correlation expression", expression);
ExpressionType expressionType = (ExpressionType) expression.getExpression();
assertEquals("Wrong number of expression evaluators in correlation expression", 1, expressionType.getExpressionEvaluator().size());
ItemPathType itemPathType = (ItemPathType) expressionType.getExpressionEvaluator().get(0).getValue();
// $account/c:attributes/my:yyy
PrismAsserts.assertPathEqualsExceptForPrefixes("path in correlation expression",
namespaces ?
new ItemPath(
new NameItemPathSegment(new QName("account"), true),
new NameItemPathSegment(new QName(SchemaConstantsGenerated.NS_COMMON, "attributes")),
new NameItemPathSegment(new QName("http://myself.me/schemas/whatever", "yyy"))
) :
new ItemPath(
new NameItemPathSegment(new QName("account"), true),
new NameItemPathSegment(new QName("attributes")),
new NameItemPathSegment(new QName("yyy"))
), itemPathType.getItemPath());
//PrismAsserts.assertAllParsedNodes(expression);
// TODO
}
}
private void assertResourceJaxb(ResourceType resourceType, boolean isSimple) throws SchemaException {
assertEquals("Wrong oid (JAXB)", TestConstants.RESOURCE_OID, resourceType.getOid());
assertEquals("Wrong name (JAXB)", PrismTestUtil.createPolyStringType("Embedded Test OpenDJ"), resourceType.getName());
String expectedNamespace = TestConstants.RESOURCE_NAMESPACE;
if (isSimple) {
expectedNamespace = MidPointConstants.NS_RI;
}
assertEquals("Wrong namespace (JAXB)", expectedNamespace, ResourceTypeUtil.getResourceNamespace(resourceType));
ObjectReferenceType connectorRef = resourceType.getConnectorRef();
assertNotNull("No connectorRef (JAXB)", connectorRef);
assertEquals("Wrong type in connectorRef (JAXB)", ConnectorType.COMPLEX_TYPE, connectorRef.getType());
SearchFilterType filter = connectorRef.getFilter();
assertNotNull("No filter in connectorRef (JAXB)", filter);
MapXNode filterElement = filter.getFilterClauseXNode();
assertNotNull("No filter element in connectorRef (JAXB)", filterElement);
EvaluationTimeType resolutionTime = connectorRef.getResolutionTime();
if (isSimple) {
assertEquals("Wrong resolution time in connectorRef (JAXB)", EvaluationTimeType.RUN, resolutionTime);
} else {
assertEquals("Wrong resolution time in connectorRef (JAXB)", EvaluationTimeType.IMPORT, resolutionTime);
}
XmlSchemaType xmlSchemaType = resourceType.getSchema();
SchemaHandlingType schemaHandling = resourceType.getSchemaHandling();
if (isSimple) {
assertNull("Schema sneaked in", xmlSchemaType);
assertNull("SchemaHandling sneaked in", schemaHandling);
} else {
assertNotNull("No schema element (JAXB)", xmlSchemaType);
SchemaDefinitionType definition = xmlSchemaType.getDefinition();
assertNotNull("No definition element in schema (JAXB)", definition);
List<Element> anyElements = definition.getAny();
assertNotNull("Null element list in definition element in schema (JAXB)", anyElements);
assertFalse("Empty element list in definition element in schema (JAXB)", anyElements.isEmpty());
assertNotNull("No schema handling (JAXB)", schemaHandling);
for(ResourceObjectTypeDefinitionType accountType: schemaHandling.getObjectType()) {
String name = accountType.getIntent();
assertNotNull("Account type without a name", name);
assertNotNull("Account type "+name+" does not have an objectClass", accountType.getObjectClass());
boolean foundDescription = false;
boolean foundDepartmentNumber = false;
for (ResourceAttributeDefinitionType attributeDefinitionType : accountType.getAttribute()) {
if ("description".equals(ItemPathUtil.getOnlySegmentQName(attributeDefinitionType.getRef()).getLocalPart())) {
foundDescription = true;
MappingType outbound = attributeDefinitionType.getOutbound();
JAXBElement<?> valueEvaluator = outbound.getExpression().getExpressionEvaluator().get(0);
System.out.println("value evaluator for description = " + valueEvaluator);
assertNotNull("no expression evaluator for description", valueEvaluator);
assertEquals("wrong expression evaluator element name for description", SchemaConstantsGenerated.C_VALUE, valueEvaluator.getName());
assertEquals("wrong expression evaluator actual type for description", RawType.class, valueEvaluator.getValue().getClass());
} else if ("departmentNumber".equals(ItemPathUtil.getOnlySegmentQName(attributeDefinitionType.getRef()).getLocalPart())) {
foundDepartmentNumber = true;
MappingType outbound = attributeDefinitionType.getOutbound();
VariableBindingDefinitionType source = outbound.getSource().get(0);
System.out.println("source for departmentNumber = " + source);
assertNotNull("no source for outbound mapping for departmentNumber", source);
//<path xmlns:z="http://z/">$user/extension/z:dept</path>
ItemPath expected = new ItemPath(
new NameItemPathSegment(new QName("user"), true),
new NameItemPathSegment(new QName("extension")),
namespaces ?
new NameItemPathSegment(new QName("http://z/", "dept")) :
new NameItemPathSegment(new QName("dept"))
);
PrismAsserts.assertPathEqualsExceptForPrefixes("source for departmentNubmer", expected, source.getPath().getItemPath());
}
}
assertTrue("ri:description attribute was not found", foundDescription);
assertTrue("ri:departmentNumber attribute was not found", foundDepartmentNumber);
}
// checking <class> element in fetch result
OperationResultType fetchResult = resourceType.getFetchResult();
assertNotNull("No fetchResult (JAXB)", fetchResult);
JAXBElement<?> value = fetchResult.getParams().getEntry().get(0).getEntryValue();
assertNotNull("No fetchResult param value (JAXB)", value);
assertEquals("Wrong value class", UnknownJavaObjectType.class, value.getValue().getClass());
UnknownJavaObjectType unknownJavaObjectType = (UnknownJavaObjectType) value.getValue();
assertEquals("Wrong value class", "my.class", unknownJavaObjectType.getClazz());
assertEquals("Wrong value toString value", "my.value", unknownJavaObjectType.getToString());
}
}
// Try to serialize it to DOM using just DOM processor. See if it does not fail.
private void serializeDom(PrismObject<ResourceType> resource) throws SchemaException {
// DomParser domProcessor = PrismTestUtil.getPrismContext().getParserDom();
// XNodeProcessor xnodeProcessor = PrismTestUtil.getPrismContext().getXnodeProcessor();
// RootXNode xnode = xnodeProcessor.serializeObject(resource);
// Element domElement = domProcessor.serializeXRootToElement(xnode);
// assertNotNull("Null resulting DOM element after DOM serialization", domElement);
}
@Test
public void testParseResourceDom() throws Exception {
if (!"xml".equals(language)) {
return;
}
final String TEST_NAME = "testParseResourceDom";
displayTestTitle(TEST_NAME);
// GIVEN
PrismContext prismContext = getPrismContext();
// WHEN
DomLexicalProcessor parserDom = ((PrismContextImpl) prismContext).getParserDom();
RootXNode xnode = parserDom.read(new ParserFileSource(getFile(TestConstants.RESOURCE_FILE_BASENAME)), ParsingContext.createDefault());
PrismObject<ResourceType> resource = prismContext.parserFor(xnode).parse();
// THEN
System.out.println("Parsed resource:");
System.out.println(resource.debugDump());
assertResource(resource, true, true, false);
}
@Test
public void testParseResourceDomSimple() throws Exception {
if (!"xml".equals(language)) {
return;
}
displayTestTitle("testParseResourceDomSimple");
// GIVEN
PrismContext prismContext = getPrismContext();
Document document = DOMUtil.parseFile(getFile(TestConstants.RESOURCE_FILE_SIMPLE_BASENAME));
Element resourceElement = DOMUtil.getFirstChildElement(document);
// WHEN
PrismObject<ResourceType> resource = prismContext.parserFor(resourceElement).parse();
// THEN
System.out.println("Parsed resource:");
System.out.println(resource.debugDump());
assertResource(resource, true, true, true);
}
}