/* * Copyright (c) 2014 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.prism.lex; import static org.testng.AssertJUnit.assertTrue; import static com.evolveum.midpoint.prism.PrismInternalTestUtil.*; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNotNull; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; import javax.xml.XMLConstants; import javax.xml.namespace.QName; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.*; import com.evolveum.midpoint.prism.foo.EventHandlerChainType; import com.evolveum.midpoint.prism.foo.EventHandlerType; import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import com.evolveum.prism.xml.ns._public.types_3.SchemaDefinitionType; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; import org.w3c.dom.Element; import org.xml.sax.SAXException; import com.evolveum.midpoint.prism.foo.ResourceType; import com.evolveum.midpoint.prism.foo.UserType; import com.evolveum.midpoint.prism.polystring.PolyString; 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.prism.xnode.XNode; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.exception.SchemaException; /** * @author semancik * */ public abstract class AbstractLexicalProcessorTest { private static final QName XSD_COMPLEX_TYPE_ELEMENT_NAME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "complexType"); public static final String EVENT_HANDLER_FILE_BASENAME = "event-handler"; @BeforeSuite public void setupDebug() throws SchemaException, SAXException, IOException { PrettyPrinter.setDefaultNamespacePrefix(DEFAULT_NAMESPACE_PREFIX); PrismTestUtil.resetPrismContext(new PrismInternalTestUtil()); } protected abstract String getSubdirName(); protected abstract String getFilenameSuffix(); protected File getCommonSubdir() { return new File(COMMON_DIR_PATH, getSubdirName()); } protected File getFile(String baseName) { return new File(getCommonSubdir(), baseName+"."+getFilenameSuffix()); } protected abstract LexicalProcessor<String> createParser(); @Test public void testParseUserToPrism() throws Exception { final String TEST_NAME = "testParseUserToPrism"; displayTestTitle(TEST_NAME); // GIVEN LexicalProcessor lexicalProcessor = createParser(); PrismContext prismContext = PrismTestUtil.getPrismContext(); // WHEN (parse to xnode) RootXNode xnode = lexicalProcessor.read(getFileSource(USER_JACK_FILE_BASENAME), ParsingContext.createDefault()); System.out.println("XNode after parsing:"); System.out.println(xnode.debugDump()); // WHEN (parse to prism) PrismObject<UserType> user = prismContext.parserFor(xnode).parse(); // THEN System.out.println("Parsed user:"); System.out.println(user.debugDump()); assertUserJackXNodeOrdering("serialized xnode", xnode); assertUserJack(user, true); } private ParserSource getFileSource(String basename) { return new ParserFileSource(getFile(basename)); } @Test public void testParseUserRoundTrip() throws Exception { final String TEST_NAME = "testParseUserRoundTrip"; displayTestTitle(TEST_NAME); // GIVEN LexicalProcessor<String> lexicalProcessor = createParser(); PrismContext prismContext = PrismTestUtil.getPrismContext(); // WHEN (parse) RootXNode xnode = lexicalProcessor.read(getFileSource(USER_JACK_FILE_BASENAME), ParsingContext.createDefault()); System.out.println("\nParsed xnode:"); System.out.println(xnode.debugDump()); PrismObject<UserType> user = prismContext.parserFor(xnode).parse(); // THEN System.out.println("\nParsed user:"); System.out.println(user.debugDump()); assertUserJack(user, true); // WHEN (re-serialize to XNode) RootXNode serializedXNode = prismContext.xnodeSerializer() .options(SerializationOptions.createSerializeCompositeObjects()) .serialize(user); String serializedString = lexicalProcessor.write(serializedXNode, new QName(NS_FOO, "user"), null); // THEN System.out.println("\nXNode after re-serialization:"); System.out.println(serializedXNode.debugDump()); System.out.println("\nRe-serialized string:"); System.out.println(serializedString); String whenSerialized = getWhenItemSerialized(); assertTrue("Serialized form does not contain " + whenSerialized, serializedString.contains(whenSerialized)); assertUserJackXNodeOrdering("serialized xnode", serializedXNode); validateUserSchema(serializedString, prismContext); // WHEN (re-parse) RootXNode reparsedXnode = lexicalProcessor.read(new ParserStringSource(serializedString), ParsingContext.createDefault()); PrismObject<UserType> reparsedUser = prismContext.parserFor(reparsedXnode).parse(); // THEN System.out.println("\nXNode after re-parsing:"); System.out.println(reparsedXnode.debugDump()); System.out.println("\nRe-parsed user:"); System.out.println(reparsedUser.debugDump()); assertUserJackXNodeOrdering("serialized xnode", reparsedXnode); ObjectDelta<UserType> diff = DiffUtil.diff(user, reparsedUser); System.out.println("\nDiff:"); System.out.println(diff.debugDump()); PrismObject accountRefObjOrig = findObjectFromAccountRef(user); PrismObject accountRefObjRe = findObjectFromAccountRef(reparsedUser); ObjectDelta<UserType> accountRefObjDiff = DiffUtil.diff(accountRefObjOrig, accountRefObjRe); System.out.println("\naccountRef object diff:"); System.out.println(accountRefObjDiff.debugDump()); assertTrue("Re-parsed object in accountRef does not match: "+accountRefObjDiff, accountRefObjDiff.isEmpty()); assertTrue("Re-parsed user does not match: "+diff, diff.isEmpty()); } // to check if timestamps are serialized correctly protected abstract String getWhenItemSerialized(); @Test public void testParseResourceRumToPrism() throws Exception { final String TEST_NAME = "testParseResourceRumToPrism"; displayTestTitle(TEST_NAME); // GIVEN LexicalProcessor lexicalProcessor = createParser(); PrismContext prismContext = PrismTestUtil.getPrismContext(); // WHEN (parse to xnode) RootXNode xnode = lexicalProcessor.read(getFileSource(RESOURCE_RUM_FILE_BASENAME), ParsingContext.createDefault()); System.out.println("XNode after parsing:"); System.out.println(xnode.debugDump()); // WHEN (parse to prism) PrismObject<ResourceType> resource = prismContext.parserFor(xnode).parse(); // THEN System.out.println("Parsed resource:"); System.out.println(resource.debugDump()); assertResourceRum(resource); } @Test public void testParseResourceRoundTrip() throws Exception { final String TEST_NAME = "testParseResourceRoundTrip"; displayTestTitle(TEST_NAME); // GIVEN LexicalProcessor<String> lexicalProcessor = createParser(); PrismContext prismContext = PrismTestUtil.getPrismContext(); // WHEN (parse) RootXNode xnode = lexicalProcessor.read(getFileSource(RESOURCE_RUM_FILE_BASENAME), ParsingContext.createDefault()); PrismObject<ResourceType> resource = prismContext.parserFor(xnode).parse(); // THEN System.out.println("\nParsed resource:"); System.out.println(resource.debugDump()); assertResourceRum(resource); // WHEN (re-serialize to XNode) XNode serializedXNode = prismContext.xnodeSerializer() .options(SerializationOptions.createSerializeCompositeObjects()) .serialize(resource); String serializedString = lexicalProcessor.write(serializedXNode, new QName(NS_FOO, "resource"), null); // THEN System.out.println("\nXNode after re-serialization:"); System.out.println(serializedXNode.debugDump()); System.out.println("\nRe-serialized string:"); System.out.println(serializedString); validateResourceSchema(serializedString, prismContext); // WHEN (re-parse) RootXNode reparsedXnode = lexicalProcessor.read(new ParserStringSource(serializedString), ParsingContext.createDefault()); PrismObject<ResourceType> reparsedResource = prismContext.parserFor(reparsedXnode).parse(); // THEN System.out.println("\nXNode after re-parsing:"); System.out.println(reparsedXnode.debugDump()); System.out.println("\nRe-parsed resource:"); System.out.println(reparsedResource.debugDump()); ObjectDelta<ResourceType> diff = DiffUtil.diff(resource, reparsedResource); System.out.println("\nDiff:"); System.out.println(diff.debugDump()); assertTrue("Re-parsed user does not match: "+diff, diff.isEmpty()); } private void assertResourceRum(PrismObject<ResourceType> resource) throws SchemaException { resource.checkConsistence(); resource.assertDefinitions("test"); assertEquals("Wrong oid", RESOURCE_RUM_OID, resource.getOid()); PrismAsserts.assertObjectDefinition(resource.getDefinition(), RESOURCE_QNAME, RESOURCE_TYPE_QNAME, ResourceType.class); PrismAsserts.assertParentConsistency(resource); assertPropertyValue(resource, "name", new PolyString("Rum Delivery System", "rum delivery system")); assertPropertyDefinition(resource, "name", PolyStringType.COMPLEX_TYPE, 0, 1); PrismProperty<SchemaDefinitionType> propSchema = resource.findProperty(ResourceType.F_SCHEMA); assertNotNull("No schema property in resource", propSchema); PrismPropertyDefinition<SchemaDefinitionType> propSchemaDef = propSchema.getDefinition(); assertNotNull("No definition of schema property in resource", propSchemaDef); SchemaDefinitionType schemaDefinitionType = propSchema.getRealValue(); assertNotNull("No value of schema property in resource", schemaDefinitionType); Element schemaElement = schemaDefinitionType.getSchema(); assertNotNull("No schema element in schema property in resource", schemaElement); System.out.println("Resource schema:"); System.out.println(DOMUtil.serializeDOMToString(schemaElement)); assertEquals("Bad schema element name", DOMUtil.XSD_SCHEMA_ELEMENT, DOMUtil.getQName(schemaElement)); Element complexTypeElement = DOMUtil.getChildElement(schemaElement, XSD_COMPLEX_TYPE_ELEMENT_NAME); assertNotNull("No complexType element in schema element in schema property in resource", complexTypeElement); String complexTypeName = complexTypeElement.getAttribute("name"); assertEquals("Wrong name of complex type", "BarrelType", complexTypeName); } private PrismObject findObjectFromAccountRef(PrismObject<UserType> user) { for (PrismReferenceValue rval: user.findReference(UserType.F_ACCOUNT_REF).getValues()) { if (rval.getObject() != null) { return rval.getObject(); } } return null; } protected <X extends XNode> X getAssertXNode(String message, XNode xnode, Class<X> expectedClass) { assertNotNull(message+" is null", xnode); assertTrue(message+", expected "+expectedClass.getSimpleName()+", was "+xnode.getClass().getSimpleName(), expectedClass.isAssignableFrom(xnode.getClass())); return (X) xnode; } protected <X extends XNode> X getAssertXMapSubnode(String message, MapXNode xmap, QName key, Class<X> expectedClass) { XNode xsubnode = xmap.get(key); assertNotNull(message+" no key "+key, xsubnode); return getAssertXNode(message+" key "+key, xsubnode, expectedClass); } protected void assertUserJackXNodeOrdering(String message, XNode xnode) { if (xnode instanceof RootXNode) { xnode = ((RootXNode)xnode).getSubnode(); } MapXNode xmap = getAssertXNode(message+": top", xnode, MapXNode.class); Set<Entry<QName, XNode>> reTopMapEntrySet = xmap.entrySet(); Iterator<Entry<QName, XNode>> reTopMapEntrySetIter = reTopMapEntrySet.iterator(); Entry<QName, XNode> reTopMapEntry0 = reTopMapEntrySetIter.next(); assertEquals(message+": Wrong entry 0, the xnodes were shuffled", "oid", reTopMapEntry0.getKey().getLocalPart()); Entry<QName, XNode> reTopMapEntry1 = reTopMapEntrySetIter.next(); assertEquals(message+": Wrong entry 1, the xnodes were shuffled", "version", reTopMapEntry1.getKey().getLocalPart()); Entry<QName, XNode> reTopMapEntry2 = reTopMapEntrySetIter.next(); assertEquals(message+": Wrong entry 2, the xnodes were shuffled", UserType.F_NAME, reTopMapEntry2.getKey()); Entry<QName, XNode> reTopMapEntry3 = reTopMapEntrySetIter.next(); assertEquals(message+": Wrong entry 3, the xnodes were shuffled", UserType.F_DESCRIPTION, reTopMapEntry3.getKey()); } protected void validateUserSchema(String dataString, PrismContext prismContext) throws SAXException, IOException { // Nothing to do by default } protected void validateResourceSchema(String dataString, PrismContext prismContext) throws SAXException, IOException { // Nothing to do by default } // The following is not supported now (and probably won't be in the future). // Enable it if that changes. @Test(enabled = false) public void testParseEventHandler() throws Exception { final String TEST_NAME = "testParseEventHandler"; displayTestTitle(TEST_NAME); // GIVEN LexicalProcessor lexicalProcessor = createParser(); PrismContext prismContext = PrismTestUtil.getPrismContext(); // WHEN (parse to xnode) RootXNode xnode = lexicalProcessor.read(getFileSource(EVENT_HANDLER_FILE_BASENAME), ParsingContext.createDefault()); System.out.println("XNode after parsing:"); System.out.println(xnode.debugDump()); // WHEN (parse to prism) EventHandlerType eventHandlerType = prismContext.parserFor(xnode).parseRealValue(EventHandlerChainType.class); // EventHandlerType eventHandlerType = prismContext.getBeanConverter().unmarshall((MapXNode) , EventHandlerChainType.class, // ParsingContext.createDefault()); // THEN System.out.println("Parsed object:"); System.out.println(eventHandlerType); // WHEN2 (marshalling) MapXNode marshalled = (MapXNode) (prismContext.xnodeSerializer().serializeRealValue(eventHandlerType).getSubnode()); System.out.println("XNode after unmarshalling and marshalling back:"); System.out.println(marshalled.debugDump()); } }