/******************************************************************************* * Copyright 2006 - 2014 Vienna University of Technology, * Department of Software Technology and Interactive Systems, IFS * * 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 eu.scape_project.planning.xml; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.XPath; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; import org.junit.Before; import org.junit.Test; import eu.scape_project.planning.exception.PlanningException; import eu.scape_project.planning.model.Alternative; import eu.scape_project.planning.model.AlternativesDefinition; import eu.scape_project.planning.model.ByteStream; import eu.scape_project.planning.model.DetailedExperimentInfo; import eu.scape_project.planning.model.DigitalObject; import eu.scape_project.planning.model.Experiment; import eu.scape_project.planning.model.Plan; import eu.scape_project.planning.model.PlanProperties; import eu.scape_project.planning.model.PlanState; import eu.scape_project.planning.model.PolicyNode; import eu.scape_project.planning.model.ProjectBasis; import eu.scape_project.planning.model.ResourceDescription; import eu.scape_project.planning.model.SampleObject; import eu.scape_project.planning.model.Trigger; import eu.scape_project.planning.model.TriggerDefinition; import eu.scape_project.planning.model.TriggerType; import eu.scape_project.planning.model.measurement.Measurement; import eu.scape_project.planning.model.tree.PolicyTree; /** * Tests for ProjectExporter. */ public class ProjectExporterTest { protected static final Map<String, String> T2FLOW_NAMESPACE_MAP = new HashMap<String, String>(); private ProjectExporter exporter; @Before public void setUp() { exporter = new ProjectExporter(); T2FLOW_NAMESPACE_MAP.put("p", PlanXMLConstants.PLATO_NS); T2FLOW_NAMESPACE_MAP.put("xsi", "http://www.w3.org/2001/XMLSchema-instance"); } @Test public void createProjectDoc() { Document doc = exporter.createProjectDoc(); assertThat(getNode(doc, "/plans"), notNullValue()); assertThat(getContent(doc, "/plans/@version"), is(PlanXMLConstants.PLATO_SCHEMA_VERSION)); } @Test public void createTemplateDoc() { Document doc = exporter.createTemplateDoc(); assertThat(getNode(doc, "/templates"), notNullValue()); } @Test public void exportToXml_planProperties() throws PlanningException { Plan p = generateBasicPlan(); p.setPlanProperties(generatePlanProperties()); Document doc = exporter.exportToXml(p); Element ppElement = (Element) getNode(doc, "/plans/p:plan/p:properties"); assertThat(ppElement.attributeValue("author"), is("Author")); assertThat(ppElement.attributeValue("organization"), is("Organization")); assertThat(ppElement.attributeValue("name"), is("Name")); assertThat(ppElement.attributeValue("privateProject"), is("true")); assertThat(ppElement.attributeValue("reportPublic"), is("true")); assertThat(ppElement.attributeValue("repositoryIdentifier"), is("Repository ID")); Element reportElement = getElement(doc, "/plans/p:plan/p:properties/p:report"); checkDigitalObject(reportElement, p.getPlanProperties().getReportUpload()); assertThat(getElement(doc, "/plans/p:plan/p:properties/p:state").attributeValue("value"), is("0")); checkContentByName(ppElement, "p:description"); checkContentByName(ppElement, "p:owner"); } @Test public void exportToXml_basis() throws PlanningException { Plan p = generateBasicPlan(); p.setProjectBasis(generateBasis()); Document doc = exporter.exportToXml(p); Element basisElement = (Element) getNode(doc, "/plans/p:plan/p:basis"); assertThat(basisElement.attributeValue("identificationCode"), is("Identification code")); checkContentByName(basisElement, "p:documentTypes"); checkContentByName(basisElement, "p:applyingPolicies"); checkContentByName(basisElement, "p:designatedCommunity"); checkContentByName(basisElement, "p:mandate"); checkContentByName(basisElement, "p:organisationalProcedures"); checkContentByName(basisElement, "p:planningPurpose"); checkContentByName(basisElement, "p:planRelations"); checkContentByName(basisElement, "p:preservationRights"); checkContentByName(basisElement, "p:referenceToAgreements"); Element newTriggerElement = getElement(basisElement, "p:triggers/p:trigger[@type='NEW_COLLECTION']"); assertThat(newTriggerElement.attributeValue("active"), is("true")); assertThat(newTriggerElement.attributeValue("description"), is("New description")); Element periodicTriggerElement = getElement(basisElement, "p:triggers/p:trigger[@type='PERIODIC_REVIEW']"); assertThat(periodicTriggerElement.attributeValue("active"), is("false")); Element ceTriggerElement = getElement(basisElement, "p:triggers/p:trigger[@type='CHANGED_ENVIRONMENT']"); assertThat(ceTriggerElement.attributeValue("active"), is("false")); assertThat(ceTriggerElement.attributeValue("description"), is("Changed environment description")); Element coTriggerElement = getElement(basisElement, "p:triggers/p:trigger[@type='CHANGED_OBJECTIVE']"); assertThat(coTriggerElement.attributeValue("active"), is("false")); Element ccpTriggerElement = getElement(basisElement, "p:triggers/p:trigger[@type='CHANGED_COLLECTION_PROFILE']"); assertThat(ccpTriggerElement.attributeValue("active"), is("false")); } @Test public void exportToXml_alternative() throws PlanningException { Plan p = generateBasicPlan(); AlternativesDefinition alternativesDefinition = new AlternativesDefinition(); alternativesDefinition.setDescription("Description"); Alternative alt1 = generateAlternative("Alternative 1"); alternativesDefinition.addAlternative(alt1); Alternative alt2 = generateAlternative("Alternative 2"); alternativesDefinition.addAlternative(alt2); p.setAlternativesDefinition(alternativesDefinition); Document doc = exporter.exportToXml(p); assertThat(getNodes(doc, "/plans/p:plan/p:alternatives/p:alternative").size(), is(2)); // Alternative 1 Element alt1Element = getElement(doc, "/plans/p:plan/p:alternatives/p:alternative[@name='Alternative 1']"); assertThat(alt1Element, notNullValue()); checkContentByName(alt1Element, "p:description"); Element ex1Element = getElement(alt1Element, "p:experiment"); checkContentByName(ex1Element, "p:description"); checkContentByName(ex1Element, "p:settings"); checkDigitalObject(getElement(ex1Element, "p:workflow"), alt1.getExperiment().getWorkflow()); Element detailedInfo1Element = getElement(ex1Element, "p:detailedInfos/p:detailedInfo"); assertThat(detailedInfo1Element.attributeValue("key"), is("Short name")); assertThat(detailedInfo1Element.attributeValue("successful"), is("true")); checkContentByName(detailedInfo1Element, "p:programOutput"); checkContentByName(detailedInfo1Element, "p:cpr"); Element measurement1Element = getElement(detailedInfo1Element, "p:measurements/p:measurement"); assertThat(measurement1Element.attributeValue("measureId"), is("Measure id")); checkContentByName(measurement1Element, "p:freeStringValue/p:value"); // Alternative 2 Element alt2Element = getElement(doc, "/plans/p:plan/p:alternatives/p:alternative[@name='Alternative 2']"); assertThat(alt2Element, notNullValue()); checkContentByName(alt2Element, "p:description"); Element ex2Element = getElement(alt1Element, "p:experiment"); checkContentByName(ex2Element, "p:description"); checkContentByName(ex2Element, "p:settings"); checkDigitalObject(getElement(ex2Element, "p:workflow"), alt1.getExperiment().getWorkflow()); assertThat(getContent(doc, "/plans/p:plan/p:alternatives/p:alternative[@name='Alternative 1']/p:experiment"), notNullValue()); } /** * TODO: Debug code, remove. * * @param doc * the document to print */ private void printDoc(Document doc) { try { PrintWriter out = new PrintWriter("/tmp/out.xml"); OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter(out, format); writer.write(doc); writer.close(); out.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Generates a basic plan. * * @return the plan */ private Plan generateBasicPlan() { Plan p = new Plan(); PlanProperties planProperties = new PlanProperties(); p.setPlanProperties(planProperties); return p; } /** * Generates an alternative. * * @param name * the alternative name * @return the alternative */ private Alternative generateAlternative(String name) { Alternative a = new Alternative(name, "Description"); a.setDiscarded(false); ResourceDescription resourceDescription = new ResourceDescription(); a.setResourceDescription(resourceDescription); Experiment experiment = new Experiment(); experiment.setDescription("Description"); experiment.setSettings("Settings"); experiment.setWorkflow(generateDigitalObject()); Map<SampleObject, DetailedExperimentInfo> detailedInfo = experiment.getDetailedInfo(); SampleObject sample1 = new SampleObject("Short name"); DetailedExperimentInfo experimentInfo1 = new DetailedExperimentInfo(); experimentInfo1.setSuccessful(true); experimentInfo1.setCpr("Cpr"); experimentInfo1.setProgramOutput("Program output"); experimentInfo1.getMeasurements().put("key", new Measurement("Measure id", "Value")); detailedInfo.put(sample1, experimentInfo1); a.setExperiment(experiment); return a; } /** * Generates plan properties. * * @return the plan properties */ private PlanProperties generatePlanProperties() { PlanProperties planProperties = new PlanProperties(); planProperties.setAuthor("Author"); planProperties.setName("Name"); planProperties.setDescription("Description"); planProperties.setOrganization("Organization"); planProperties.setOwner("Owner"); planProperties.setPrivateProject(true); planProperties.setReportPublic(true); planProperties.setRepositoryIdentifier("Repository ID"); planProperties.setReportUpload(generateDigitalObject()); planProperties.setState(PlanState.CREATED); return planProperties; } /** * Generates a project basis. * * @return the project basis */ private ProjectBasis generateBasis() { ProjectBasis basis = new ProjectBasis(); basis.setIdentificationCode("Identification code"); basis.setDocumentTypes("Document types"); basis.setMandate("Mandate"); basis.setPlanningPurpose("Planning purpose"); basis.setDesignatedCommunity("Designated community"); basis.setApplyingPolicies("Applying policies"); basis.setOrganisationalProcedures("Organisational procedures"); basis.setPreservationRights("Preservation rights"); basis.setReferenceToAgreements("Reference to agreements"); basis.setPlanRelations("Plan relations"); TriggerDefinition triggers = new TriggerDefinition(); Trigger newTrigger = new Trigger(TriggerType.NEW_COLLECTION); newTrigger.setActive(true); newTrigger.setDescription("New description"); triggers.setTrigger(newTrigger); Trigger ceTrigger = new Trigger(TriggerType.CHANGED_ENVIRONMENT); ceTrigger.setActive(false); ceTrigger.setDescription("Changed environment description"); triggers.setTrigger(ceTrigger); triggers.setTrigger(new Trigger(TriggerType.CHANGED_COLLECTION_PROFILE)); basis.setTriggers(triggers); PolicyTree policyTree = new PolicyTree(); PolicyNode root = new PolicyNode(); root.setName("Root node"); PolicyNode child1 = new PolicyNode(); child1.setName("Child 1"); child1.setParent(root); root.getChildren().add(child1); policyTree.setRoot(root); basis.setPolicyTree(policyTree); return basis; } /** * Generates a digital object. * * @return the digital object */ private DigitalObject generateDigitalObject() { DigitalObject d = new DigitalObject(); d.setContentType("application/vnd.taverna.t2flow+xml"); d.setFullname("workflow.t2flow"); d.setPid("pid-experiment-workflow"); ByteStream bs = new ByteStream(); bs.setData("workflowdata".getBytes()); d.setData(bs); return d; } private void checkDigitalObject(Element element, DigitalObject digitalObject) { assertThat(element.attributeValue("fullname"), is(digitalObject.getFullname())); assertThat(element.attributeValue("contentType"), is(digitalObject.getContentType())); Element dataElement = (Element) createXPath("p:data").selectSingleNode(element); assertThat(dataElement.attributeValue("hasData"), is("true")); assertThat(dataElement.attributeValue("encoding"), is("base64")); } /** * Checks if the content of the specified node against the nodes name. The * node name is coverter with: * Camel case separated into words * The first * letter capitalized * All other letters lowercased * * @param context * the search context * @param xPath * the xPath */ private void checkContentByName(Node context, String xPath) { String content = getContent(context, xPath); String xPathText = xPath.replaceAll(".+:", "").replaceAll("([A-Z])", " $1"); xPathText = xPathText.substring(0, 1).toUpperCase() + xPathText.substring(1).toLowerCase(); assertThat(content, is(xPathText)); } /** * Creates an xPath element including namespaces. * * @param xPath * the xPath * @return the xPath object */ private XPath createXPath(String xPath) { XPath x = DocumentHelper.createXPath("p:data"); x.setNamespaceURIs(T2FLOW_NAMESPACE_MAP); return x; } /** * Returns nodes of the provided document identified by the xPath. * * @param context * the search context * @param xPath * the xPath to search * @return a list of nodes */ @SuppressWarnings("unchecked") private List<Node> getNodes(Node context, String xPath) { XPath x = DocumentHelper.createXPath(xPath); x.setNamespaceURIs(T2FLOW_NAMESPACE_MAP); return x.selectNodes(context); } /** * Returns a single node of the provided document identified by the xPath. * * @param context * the search context * @param xPath * the xPath to search * @return a single node or null if none found */ @SuppressWarnings("unchecked") private Node getNode(Node context, String xPath) { XPath x = DocumentHelper.createXPath(xPath); x.setNamespaceURIs(T2FLOW_NAMESPACE_MAP); List<Node> nodes = x.selectNodes(context); assertThat(nodes.size(), is(1)); return nodes.get(0); } /** * Returns a single element of the provided document identified by the * xPath. * * @param context * the search context * @param xPath * the xPath to search * @return a single node or null if none found */ private Element getElement(Node context, String xPath) { return (Element) getNode(context, xPath); } /** * Returns the content of a single node. * * @param context * the search context * @param xPath * the xPath to search * @return content of a single node or null if none found */ private String getContent(Node context, String xPath) { Node n = getNode(context, xPath); if (n == null) { return null; } else { return n.getText(); } } }