Package eu.scape_project.planning.xml

Source Code of eu.scape_project.planning.xml.ProjectExporter

/*******************************************************************************
* 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 java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.codec.binary.Base64;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.scape_project.planning.exception.PlanningException;
import eu.scape_project.planning.model.Alternative;
import eu.scape_project.planning.model.ChangeLog;
import eu.scape_project.planning.model.DetailedExperimentInfo;
import eu.scape_project.planning.model.DigitalObject;
import eu.scape_project.planning.model.ExecutablePlanDefinition;
import eu.scape_project.planning.model.Experiment;
import eu.scape_project.planning.model.Parameter;
import eu.scape_project.planning.model.Plan;
import eu.scape_project.planning.model.PlanDefinition;
import eu.scape_project.planning.model.Policy;
import eu.scape_project.planning.model.PolicyNode;
import eu.scape_project.planning.model.SampleObject;
import eu.scape_project.planning.model.TargetValueObject;
import eu.scape_project.planning.model.Trigger;
import eu.scape_project.planning.model.measurement.Attribute;
import eu.scape_project.planning.model.measurement.CriterionCategory;
import eu.scape_project.planning.model.measurement.Measure;
import eu.scape_project.planning.model.measurement.Measurement;
import eu.scape_project.planning.model.scales.FreeStringScale;
import eu.scape_project.planning.model.scales.RestrictedScale;
import eu.scape_project.planning.model.scales.Scale;
import eu.scape_project.planning.model.scales.ScaleType;
import eu.scape_project.planning.model.transform.NumericTransformer;
import eu.scape_project.planning.model.transform.OrdinalTransformer;
import eu.scape_project.planning.model.tree.Leaf;
import eu.scape_project.planning.model.tree.TemplateTree;
import eu.scape_project.planning.model.tree.TreeNode;
import eu.scape_project.planning.model.util.FloatFormatter;
import eu.scape_project.planning.model.values.Value;
import eu.scape_project.planning.xml.plan.TimestampFormatter;

/**
* Static methods providing means to export projects to XML using dom4j.
*
* @author Michael Kraxner, Markus Hamm
*/
public class ProjectExporter implements Serializable {
    private static final long serialVersionUID = 7538933914251415135L;

    private static final Base64 encoder = new Base64(PlanXMLConstants.BASE64_LINE_LENGTH, PlanXMLConstants.BASE64_LINE_BREAK);

    private Logger log = LoggerFactory.getLogger(ProjectExporter.class);;

    private TimestampFormatter formatter = new TimestampFormatter();
    private FloatFormatter floatFormatter = new FloatFormatter();

    public static OutputFormat prettyFormat = new OutputFormat(" ", true, PlanXMLConstants.ENCODING); // OutputFormat.createPrettyPrint();
    public static OutputFormat compactFormat = new OutputFormat(null, false, PlanXMLConstants.ENCODING); // OutputFormat.createPrettyPrint();

    private static final Namespace XSI_NAMESPACE = new Namespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
    private static final Namespace PLATO_NAMESPACE = new Namespace("", PlanXMLConstants.PLATO_NS);

    public ProjectExporter() {
    }

//    /**
//     * Returns the xml-representation of the given project as a String. NOTE: It
//     * writes all data - including encoded binary data - directly to the DOM
//     * tree this may result in performance problems for large amounts of data.
//     *
//     * @param p
//     *            the plan to export
//     * @return the XML representation of the plan
//     * @throws PlanningException
//     *             if an error occured during export
//     */
//    public String exportToString(Plan p) throws PlanningException {
//        return exportToXml(p).asXML();
//    }

    /**
     * Takes the given project and turns it into a dom4j-xml-representation.
     *
     * NOTE: It does NOT write the binary data, but only the ids instead !
     *
     * @param p
     *            the plan to export
     * @return dom4j-document representing the given project
     * @throws PlanningException
     *             if an error occured during export
     */
    public Document exportToXml(Plan p) throws PlanningException {
        Document doc = createProjectDoc();
        addProject(p, doc, false);
        return doc;
    }

    /**
     * Creates a dom4j document template to add plans.
     *
     * @return the dom4j document
     */
    public Document createProjectDoc() {
        Document doc = DocumentHelper.createDocument();

        Element root = doc.addElement("plans");

        root.add(XSI_NAMESPACE);
        root.add(PLATO_NAMESPACE);
        root.addAttribute(XSI_NAMESPACE.getPrefix() + ":schemaLocation", PlanXMLConstants.PLATO_NS + " "
            + PlanXMLConstants.PLATO_SCHEMA);
        root.add(new Namespace("fits", "http://hul.harvard.edu/ois/xml/ns/fits/fits_output"));

        // set version of corresponding schema
        root.addAttribute("version", PlanXMLConstants.PLATO_SCHEMA_VERSION);

        return doc;
    }

    /**
     * Creates a template document.
     *
     * @return the dom4j-document
     */
    public Document createTemplateDoc() {
        Document doc = DocumentHelper.createDocument();

        Element root = doc.addElement("templates");

        root.add(XSI_NAMESPACE);

        return doc;
    }

    /**
     * This method creates a template xml from the objective tree contained in
     * Plan p. The template xml is of the form
     *
     * <templates> <template name="Public Fragments"> <node name="Template 1"
     * weight="0.0" single="false" lock="false"> <node
     * name="Interactive multimedia presentations" weight="0.0" single="false"
     * lock="false"> ... </template> </templates>
     *
     * For creating the tree we use
     * {@link ProjectExporter#addSubTree(TreeNode, Element)} and remove
     * afterwards the evaluation part which we don't want to have in the
     * template.
     *
     * @param p
     *            preservation plan
     * @param templateLibrary
     *            name of the template library (e.g. 'Public Templates')
     * @param name
     *            name of the template
     * @param description
     *            description of the template
     * @return xml as string
     */
    public String getObjectiveTreeAsTemplate(Plan p, String templateLibrary, String name, String description) {
        Document templateDoc = createTemplateDoc();

        Element template = templateDoc.getRootElement().addElement("template");
        template.addAttribute("name", templateLibrary);

        // Objectivetree (including weights, evaluation values and transformers)
        if (p.getTree().getRoot() != null) {
            addSubTree(p.getTree().getRoot(), template);
        }

        // get the root node of the tree
        Element treeRootNode = (Element) template.selectSingleNode("//templates/template/node");

        // change the name of the template
        if (name == null) {
            name = "";
        }
        treeRootNode.addAttribute("name", name);

        if (description == null) {
            description = "";
        }
        // set the description of the template
        Element descriptionElement = treeRootNode.addElement("description");
        descriptionElement.setText(description);

        // remove the evaluation from the template
        @SuppressWarnings("unchecked")
        List<Element> nodes = templateDoc.selectNodes("//leaf/evaluation");

        for (Element n : nodes) {
            n.getParent().remove(n);
        }

        return templateDoc.asXML();
    }

    /**
     * Takes the given projects and turns them into a dom4j-xml-representation.
     * NOTE: It writes all data - including encoded binary data - directly to
     * the DOM tree this may result in performance problems for large amounts of
     * data.
     *
     * @return dom4j-document representing the given project public static
     *         Document exportToXml(List<Plan> projects) { Document doc =
     *         createProjectDoc();
     *
     *         for (Plan project : projects) {
     *         ProjectExporter.addProject(project, doc, null, null); } return
     *         doc; }
     */

    /**
     * Writes the xml-representation of the given projects to the given target
     * file. NOTE: It writes all data - including encoded binary data - directly
     * to the DOM tree this may result in performance problems for large amounts
     * of data.
     *
     * @param p
     *            the plan to export
     * @param target
     *            the file to write the plan
     * @throws IOException
     *             if an error occured during write
     * @throws PlanningException
     *             if an error occured during export
     */
    public void exportToFile(Plan p, File target) throws IOException, PlanningException {
        XMLWriter writer = new XMLWriter(new FileWriter(target), ProjectExporter.prettyFormat);
        try {
            writer.write(exportToXml(p));
        } finally {
            writer.close();
        }
    }

//    /**
//     * Writes the xml-representation of the given project into a temporary file
//     * and returns the java-representation of this file. NOTE: It writes all
//     * data - including encoded binary data - directly to the DOM tree this may
//     * result in performance problems for large amounts of data.
//     *
//     * @param p
//     *            the plan to export
//     * @throws IOException
//     *             if an error occured during export
//     * @throws PlanningException
//     *             if an error occured during export
//     *
//     */
//    public File exportToFile(Plan p) throws IOException, PlanningException {
//        File temp = File.createTempFile("plato-plan-export-", ".xml");
//        exportToFile(p, temp);
//        return temp;
//    }

    /*
     * public static File exportTemplatesToFile(List<TemplateTree> trees) throws
     * IOException { File temp = File.createTempFile("plato-templates-export-",
     * ".xml"); XMLWriter writer = new XMLWriter(new FileWriter(temp),
     * ProjectExporter.prettyFormat); //writer.setMaximumAllowedCharacter(127);
     * writer.write(ProjectExporter.exportTemplates(trees)); writer.close();
     * return temp; }
     */

    public Document exportTemplates(List<TemplateTree> trees) {
        Document doc = DocumentHelper.createDocument();

        Element root = doc.addElement("templates");

        for (TemplateTree template : trees) {
            addTemplateTree(template, root);
        }
        return doc;
    }

    /**
     * Adds the XML representation of the complete template tree to the parent
     * node <code>root</code>.
     *
     * @param tree
     * @param root
     */
    private void addTemplateTree(TemplateTree tree, Element root) {
        Element template = root.addElement("template");
        template.addAttribute("name", tree.getName());
        template.addAttribute("owner", tree.getOwner());
        for (TreeNode child : tree.getRoot().getChildren()) {
            addSubTree(child, template);
        }
    }

    private void addSubPolicyTree(PolicyNode data, Element xmlRoot) {

        if (data == null) {
            return;
        }

        if (data.isPolicy()) {
            Element policy = xmlRoot.addElement("policy");

            Policy p = (Policy) data;

            policy.addAttribute("name", p.getName());
            policy.addAttribute("value", p.getValue());
        } else {
            Element policyNode = xmlRoot.addElement("policyNode");

            policyNode.addAttribute("name", data.getName());

            for (PolicyNode pn : data.getChildren()) {
                addSubPolicyTree(pn, policyNode);
            }
        }
    }

    /**
     * Adds the XML-representation of the treenode <code>data</code> to the
     * parent node <code>xmlRoot</code>. (also called recursivly for its
     * children)
     *
     * @param data
     * @param xmlRoot
     */
    private void addSubTree(TreeNode data, Element xmlRoot) {
        if (data.isLeaf()) {
            Element leaf = xmlRoot.addElement("leaf");
            addNodeAttributes(data, leaf);
            Leaf l = (Leaf) data;
            leaf.addElement("aggregationMode").addAttribute("value", l.getAggregationMode().name());

            String typename = null;
            /*
             * Scale: A special element is created, depending on the type of the
             * scale
             */
            Scale s = l.getScale();

            if (s != null) {
                typename = deriveElementname(s.getClass());

                addScale(s, leaf);

                // Transformer
                if (l.getTransformer() != null) {
                    Element transformer = leaf.addElement(deriveElementname(l.getTransformer().getClass()));

                    if (l.getTransformer() instanceof OrdinalTransformer) {

                        Map<String, TargetValueObject> mapping = ((OrdinalTransformer) l.getTransformer()).getMapping();
                        Element mappings = transformer.addElement("mappings");
                        for (String ordinal : mapping.keySet()) {
                            mappings
                                .addElement("mapping")
                                .addAttribute("ordinal", ordinal)
                                .addAttribute("target",
                                    floatFormatter.formatFloatPrecisly(mapping.get(ordinal).getValue()));
                        }
                    }
                    if (l.getTransformer() instanceof NumericTransformer) {
                        NumericTransformer nt = (NumericTransformer) l.getTransformer();
                        transformer.addElement("mode").addAttribute("value", nt.getMode().name());
                        Element thresholds = transformer.addElement("thresholds");
                        thresholds.addElement("threshold1").setText(
                            floatFormatter.formatFloatPrecisly(nt.getThreshold1()));
                        thresholds.addElement("threshold2").setText(
                            floatFormatter.formatFloatPrecisly(nt.getThreshold2()));
                        thresholds.addElement("threshold3").setText(
                            floatFormatter.formatFloatPrecisly(nt.getThreshold3()));
                        thresholds.addElement("threshold4").setText(
                            floatFormatter.formatFloatPrecisly(nt.getThreshold4()));
                        thresholds.addElement("threshold5").setText(
                            floatFormatter.formatFloatPrecisly(nt.getThreshold5()));

                    }
                    addChangeLog(l.getTransformer().getChangeLog(), transformer);
                }

                if (l.isMapped()) {
                    addMeasure(l.getMeasure(), leaf);
                }

                Element eval = leaf.addElement("evaluation");
                typename = typename.substring(0, typename.lastIndexOf("Scale"));
                /*
                 * keep in mind: there are only values of the considered
                 * alternatives in the map
                 */
                for (String a : l.getValueMap().keySet()) {
                    Element alt = eval.addElement("alternative");
                    alt.addAttribute("key", a);
                    addStringElement(alt, "comment", l.getValueMap().get(a).getComment());
                    for (Value v : l.getValueMap().get(a).getList()) {
                        /*
                         * A special element is created, depending on the type
                         * of the scale
                         */
                        Element valElement = alt.addElement(typename + "Result");
                        String valueStr = v.toString();
                        if (!"".equals(valueStr)) {
                            addStringElement(valElement, "value", v.toString());
                        }
                        addStringElement(valElement, "comment", v.getComment());
                        addChangeLog(v.getChangeLog(), valElement);

                    }
                }
            }

        } else { // not a leaf
            Element node = xmlRoot.addElement("node");
            addNodeAttributes(data, node);

            for (TreeNode child : data.getChildren()) {
                addSubTree(child, node);
            }
        }

    }

    /**
     * creates a new element with all information of the given measure and adds
     * it to the parent node.
     *
     * @param info
     * @param parent
     */
    private void addMeasure(Measure measure, Element parent) {
        Element measureEl = parent.addElement("measure");

        measureEl.addAttribute("ID", measure.getUri());
        addStringElement(measureEl, "name", measure.getName());
        addStringElement(measureEl, "description", measure.getDescription());

        Attribute attribute = (Attribute) measure.getAttribute();
        if (attribute != null) {
            Element attributeEl = measureEl.addElement("attribute");
            attributeEl.addAttribute("ID", attribute.getUri());
            addStringElement(attributeEl, "name", attribute.getName());
            addStringElement(attributeEl, "description", attribute.getDescription());

            CriterionCategory category = attribute.getCategory();
            Element categoryEl = attributeEl.addElement("category");
            categoryEl.addAttribute("ID", category.getUri());
            categoryEl.addAttribute("scope", category.getScope().toString());
            addStringElement(categoryEl, "name", category.getName());
        }
        addScale(measure.getScale(), measureEl);

        // addChangeLog(measure.getChangeLog(), measureEl);
    }

    /**
     * Adds the given node's properties to the xmlNode.
     */
    private void addNodeAttributes(TreeNode data, Element xmlNode) {
        xmlNode.addAttribute("name", data.getName()).addAttribute("weight",
            floatFormatter.formatFloatPrecisly(data.getWeight()));
        if (data instanceof Leaf) {
            xmlNode.addAttribute("single", Boolean.toString(data.isSingle()));
        }
        xmlNode.addAttribute("lock", Boolean.toString(data.isLock()));

        addStringElement(xmlNode, "description", data.getDescription());

        addChangeLog(data.getChangeLog(), xmlNode);
    }

    /**
     * Adds a changelog element to the provided parent if changelog is defined.
     *
     * @param log
     *            the changelog to add
     * @param parent
     *            the parent element
     * @return the newly created element or null
     */
    private Element addChangeLog(ChangeLog log, Element parent) {
        Element xmlNode = null;
        if (log != null) {
            xmlNode = parent.addElement("changelog")
                .addAttribute("created", formatter.formatTimestamp(log.getCreated()))
                .addAttribute("createdBy", log.getCreatedBy())
                .addAttribute("changed", formatter.formatTimestamp(log.getChanged()))
                .addAttribute("changedBy", log.getChangedBy());
        }
        return xmlNode;
    }

    /**
     * Adds the digital object to the parentNode. If the object is null or has
     * no data, it is not added.
     *
     * @param upload
     *            the DigitalObject to add
     * @param parent
     *            the parent element of the element to create
     * @param elementName
     *            the name of the element to create
     * @param addDigitalObjectData
     *            true if the data should be written, false otherwise
     * @return the newly created element or null if none was created
     * @throws PlanningException
     *             if an error occured during export
     */
    private Element addUpload(DigitalObject upload, Element parent, String elementName, boolean addDigitalObjectData) throws PlanningException {
        Element xmlNode = null;
        if (upload != null && upload.isDataExistent()) {
            xmlNode = addEncodedDigitalObject(upload, parent, elementName, addDigitalObjectData);
        }
        return xmlNode;
    }

    /**
     * Adds the digital object to the parentNode. If the object is null it is
     * not added.
     *
     * @param upload
     *            the DigitalObject to add
     * @param parent
     *            the parent element of the element to create
     * @param elementName
     *            the name of the element to create
     * @param addDigitalObjectData
     *            true if the data should be written, false otherwise
     * @return the newly created element or null if none was created
     * @throws PlanningException
     *             if an error occured during export
     */
    private Element addEncodedDigitalObject(DigitalObject upload, Element parent, String elementName, boolean addDigitalObjectData) throws PlanningException {

        Element xmlNode = null;
        if (upload != null) {
            xmlNode = parent.addElement(elementName);
            xmlNode.addAttribute("fullname", upload.getFullname()).addAttribute("contentType", upload.getContentType());

            Element data = xmlNode.addElement("data");
            if (upload.isDataExistent()) {
                data.addAttribute("hasData", "true");
                data.addAttribute("encoding", "base64");
                if (!addDigitalObjectData) {
                    // Add only DigitalObject ID, it can be replaced later
                    data.setText(String.valueOf(upload.getId()));
                } else {
                    // Add encoded data
                    data.setText(encodeBase64(upload.getData().getData()));
                }
            } else {
                data.addAttribute("hasData", "false");
            }

            addUpload(upload.getXcdlDescription(), xmlNode, "xcdlDescription", addDigitalObjectData);
            addJhoveInfo(upload, xmlNode);
            addFitsInfo(upload, xmlNode);
            Element formatInfo = xmlNode.addElement("formatInfo")
                .addAttribute("puid", upload.getFormatInfo().getPuid())
                .addAttribute("name", upload.getFormatInfo().getName())
                .addAttribute("version", upload.getFormatInfo().getVersion())
                .addAttribute("mimeType", upload.getFormatInfo().getMimeType())
                .addAttribute("defaultExtension", upload.getFormatInfo().getDefaultExtension());
            addChangeLog(upload.getFormatInfo().getChangeLog(), formatInfo);
            addChangeLog(upload.getChangeLog(), xmlNode);
        }
        return xmlNode;
    }

    /**
     * Adds the Jhove information of the digital object to the provided element
     * if it has one.
     *
     * @param digitalObject
     *            the digital object
     * @param parent
     *            the parent element of the element to create
     * @return the newly created element or null if none was created
     * @throws PlanningException
     *             if an error occured during export
     */
    private Element addJhoveInfo(DigitalObject digitalObject, Element parent)
        throws PlanningException {
        Element jhoveElement = null;
        String jhoveXML = digitalObject.getJhoveXMLString();
        if ((jhoveXML != null) && (!"".equals(jhoveXML))) {
            jhoveElement = parent.addElement("jhoveXML");
            jhoveElement.addAttribute("encoding", "base64");
            try {
                jhoveElement.setText(encodeBase64(jhoveXML.getBytes(PlanXMLConstants.ENCODING)));
            } catch (UnsupportedEncodingException e) {
                log.error("Error writing JHOVE info {}.", e.getMessage());
                throw new PlanningException("Error writing JHOVE info.", e);
            }
        }
        return jhoveElement;
    }

    /**
     * Adds the fits information of the digital object to the provided element
     * if it has one.
     *
     * @param digitalObject
     *            the digital object
     * @param parent
     *            the parent element of the element to create
     * @return the newly created element or null if none was created
     * @throws PlanningException
     *             if an error occured during export
     */
    private Element addFitsInfo(DigitalObject digitalObject, Element parent)
        throws PlanningException {
        Element fitsElement = null;
        String fitsInfo = digitalObject.getFitsXMLString();
        if ((fitsInfo != null) && (!"".equals(fitsInfo))) {
            fitsElement = parent.addElement("fitsXML");
            fitsElement.addAttribute("encoding", "base64");
            try {
                fitsElement.setText(encodeBase64(fitsInfo.getBytes(PlanXMLConstants.ENCODING)));
            } catch (UnsupportedEncodingException e) {
                log.error("Error writing fits info {}.", e.getMessage());
                throw new PlanningException("Error writing fits info.", e);
            }
        }
        return fitsElement;
    }

    /**
     * Creates an element name from the provided class.
     *
     * @param c
     *            the class to use
     * @return an element name
     */
    private String deriveElementname(Class<?> c) {
        String name = c.getName();
        name = name.substring(name.lastIndexOf(".") + 1);
        name = name.substring(0, 1).toLowerCase() + name.substring(1);
        return name;
    }

    /**
     * Adds the XML-representation of the given project to the parent
     * <code>projectNode</code>.
     *
     * @param p
     *            the plan to add
     * @param projectsDoc
     *            the document where the plan should be added
     * @param addDigitalObjectData
     *            whether the digital object data should be added to the XML
     * @throws PlanningException
     *             if an error occured during export
     */
    public void addProject(Plan p, Document projectsDoc, boolean addDigitalObjectData) throws PlanningException {

        Element projectNode = projectsDoc.getRootElement().addElement(new QName("plan", PLATO_NAMESPACE));

        addChangeLog(p.getChangeLog(), projectNode);

        Element properties = projectNode.addElement("properties");
        addUpload(p.getPlanProperties().getReportUpload(), properties, "report", addDigitalObjectData);

        // Plan state
        properties.addElement("state").addAttribute("value",
            Integer.toString(p.getPlanProperties().getState().getValue()));

        // Plan properties
        properties.addAttribute("author", p.getPlanProperties().getAuthor())
            .addAttribute("organization", p.getPlanProperties().getOrganization())
            .addAttribute("name", p.getPlanProperties().getName())
            .addAttribute("privateProject", Boolean.toString(p.getPlanProperties().isPrivateProject()))
            .addAttribute("reportPublic", Boolean.toString(p.getPlanProperties().isReportPublic()))
            .addAttribute("repositoryIdentifier", p.getPlanProperties().getRepositoryIdentifier())
            .addAttribute("playground", Boolean.toString(p.getPlanProperties().isPlayground()));
        addStringElement(properties, "description", p.getPlanProperties().getDescription());
        addStringElement(properties, "owner", p.getPlanProperties().getOwner());
        addChangeLog(p.getPlanProperties().getChangeLog(), properties);

        // Plan Basis
        Element basis = projectNode.addElement("basis");
        basis.addAttribute("identificationCode", p.getProjectBasis().getIdentificationCode());

        addStringElement(basis, "documentTypes", p.getProjectBasis().getDocumentTypes());
        addStringElement(basis, "applyingPolicies", p.getProjectBasis().getApplyingPolicies());
        addStringElement(basis, "designatedCommunity", p.getProjectBasis().getDesignatedCommunity());
        addStringElement(basis, "mandate", p.getProjectBasis().getMandate());
        addStringElement(basis, "organisationalProcedures", p.getProjectBasis().getOrganisationalProcedures());
        addStringElement(basis, "planningPurpose", p.getProjectBasis().getPlanningPurpose());
        addStringElement(basis, "planRelations", p.getProjectBasis().getPlanRelations());
        addStringElement(basis, "preservationRights", p.getProjectBasis().getPreservationRights());
        addStringElement(basis, "referenceToAgreements", p.getProjectBasis().getReferenceToAgreements());

        Element triggers = basis.addElement("triggers");
        if (p.getProjectBasis().getTriggers() != null) {
            addTrigger(p.getProjectBasis().getTriggers().getNewCollection(), triggers);
            addTrigger(p.getProjectBasis().getTriggers().getPeriodicReview(), triggers);
            addTrigger(p.getProjectBasis().getTriggers().getChangedEnvironment(), triggers);
            addTrigger(p.getProjectBasis().getTriggers().getChangedObjective(), triggers);
            addTrigger(p.getProjectBasis().getTriggers().getChangedCollectionProfile(), triggers);
        }

        Element policyTree = basis.addElement("policyTree");

        addSubPolicyTree(p.getProjectBasis().getPolicyTree().getRoot(), policyTree);

        addChangeLog(p.getProjectBasis().getChangeLog(), basis);

        // Sample Records
        Element samplerecords = projectNode.addElement("sampleRecords");
        addStringElement(samplerecords, "samplesDescription", p.getSampleRecordsDefinition().getSamplesDescription());

        Element collectionProfile = samplerecords.addElement("collectionProfile");
        if (p.getSampleRecordsDefinition().getCollectionProfile() != null) {
            addStringElement(collectionProfile, "collectionID", p.getSampleRecordsDefinition().getCollectionProfile()
                .getCollectionID());
            addStringElement(collectionProfile, "description", p.getSampleRecordsDefinition().getCollectionProfile()
                .getDescription());
            addStringElement(collectionProfile, "expectedGrowthRate", p.getSampleRecordsDefinition()
                .getCollectionProfile().getExpectedGrowthRate());
            addStringElement(collectionProfile, "numberOfObjects", p.getSampleRecordsDefinition()
                .getCollectionProfile().getNumberOfObjects());
            addStringElement(collectionProfile, "typeOfObjects", p.getSampleRecordsDefinition().getCollectionProfile()
                .getTypeOfObjects());
            addStringElement(collectionProfile, "retentionPeriod", p.getSampleRecordsDefinition()
                .getCollectionProfile().getRetentionPeriod());
            addUpload(p.getSampleRecordsDefinition().getCollectionProfile().getProfile(), collectionProfile, "profile",
                addDigitalObjectData);
        }

        for (SampleObject rec : p.getSampleRecordsDefinition().getRecords()) {
            Element sampleRecord = addEncodedDigitalObject(rec, samplerecords, "record", addDigitalObjectData);

            if (sampleRecord != null) {
                sampleRecord.addAttribute("shortName", rec.getShortName());
                addStringElement(sampleRecord, "description", rec.getDescription());
                addStringElement(sampleRecord, "originalTechnicalEnvironment", rec.getOriginalTechnicalEnvironment());
            }
        }
        addChangeLog(p.getSampleRecordsDefinition().getChangeLog(), samplerecords);

        // Requirementsdefinition
        Element rdef = projectNode.addElement("requirementsDefinition");
        addStringElement(rdef, "description", p.getRequirementsDefinition().getDescription());
        Element uploads = rdef.addElement("uploads");
        for (DigitalObject upload : p.getRequirementsDefinition().getUploads()) {
            addUpload(upload, uploads, "upload", addDigitalObjectData);
        }
        addChangeLog(p.getRequirementsDefinition().getChangeLog(), rdef);

        // Alternatives
        Element alternatives = projectNode.addElement("alternatives");
        addStringElement(alternatives, "description", p.getAlternativesDefinition().getDescription());

        for (Alternative a : p.getAlternativesDefinition().getAlternatives()) {
            /*
             * Export all alternatives (also discarded ones) Indices of the
             * result-set reference only the considered alternatives!
             */
            Element alt = alternatives.addElement("alternative")
                .addAttribute("discarded", Boolean.toString(a.isDiscarded())).addAttribute("name", a.getName());
            addStringElement(alt, "description", a.getDescription());
            if (a.getAction() != null) {
                Element action = alt.addElement("action");
                action.addAttribute("shortname", a.getAction().getShortname())
                    .addAttribute("url", a.getAction().getUrl())
                    .addAttribute("actionIdentifier", a.getAction().getActionIdentifier())
                    .addAttribute("info", a.getAction().getInfo())
                    .addAttribute("targetFormat", a.getAction().getTargetFormat())
                    .addAttribute("executable", String.valueOf(a.getAction().isExecutable()));
                addStringElement(action, "descriptor", a.getAction().getDescriptor());
                addStringElement(action, "parameterInfo", a.getAction().getParameterInfo());

                Element params = action.addElement("params");
                if (a.getAction().getParams() != null) {
                    for (Parameter param : a.getAction().getParams()) {
                        params.addElement("param").addAttribute("name", param.getName())
                            .addAttribute("value", param.getValue());
                    }
                }
                addChangeLog(a.getAction().getChangeLog(), action);
            }

            Element resourceDescr = alt.addElement("resourceDescription");
            addStringElement(resourceDescr, "necessaryResources", a.getResourceDescription().getNecessaryResources());
            addStringElement(resourceDescr, "configSettings", a.getResourceDescription().getConfigSettings());
            addStringElement(resourceDescr, "reasonForConsidering", a.getResourceDescription()
                .getReasonForConsidering());
            addChangeLog(a.getResourceDescription().getChangeLog(), resourceDescr);

            Element experiment = alt.addElement("experiment");
            Experiment exp = a.getExperiment();
            addStringElement(experiment, "description", exp.getDescription());
            addStringElement(experiment, "settings", exp.getSettings());
            addUpload(exp.getWorkflow(), experiment, "workflow", addDigitalObjectData);
            Element results = experiment.addElement("results");
            for (Entry<SampleObject, DigitalObject> entry : exp.getResults().entrySet()) {
                Element result = addUpload(entry.getValue(), results, "result",  addDigitalObjectData);
                if (result != null) {
                    result.addAttribute("key", entry.getKey().getShortName());
                }
            }

            // // */experiment/xcdlDescriptions/xcdlDescription
            // Element xcdls = experiment.addElement("xcdlDescriptions");
            // for (SampleObject record : exp.getResults().keySet()) {
            // DigitalObject result = exp.getResults().get(record);
            // if (result != null) {
            // XcdlDescription x = result.getXcdlDescription();
            // if (x != null) {
            // // only existing xcdls are exported
            // Element upload = addUpload(x, xcdls, "xcdlDescription",
            // encoder, uploadIDs);
            // if (upload != null) {
            // upload.addAttribute("key", record.getShortName());
            // }
            // }
            // }
            // }

            // export detailed experiment info's
            Element detailedInfos = experiment.addElement("detailedInfos");
            for (SampleObject record : exp.getDetailedInfo().keySet()) {
                DetailedExperimentInfo dinfo = exp.getDetailedInfo().get(record);
                Element detailedInfo = detailedInfos.addElement("detailedInfo")
                    .addAttribute("key", record.getShortName()).addAttribute("successful", "" + dinfo.getSuccessful());
                addStringElement(detailedInfo, "programOutput", dinfo.getProgramOutput());
                addStringElement(detailedInfo, "cpr", dinfo.getCpr());

                Element measurements = detailedInfo.addElement("measurements");
                for (Measurement m : dinfo.getMeasurements().values()) {
                    Element measurement = measurements.addElement("measurement");
                    measurement.addAttribute("measureId", m.getMeasureId());

                    // measurement.value:
                    String typename = deriveElementname(m.getValue().getClass());

                    Element valueElem = measurement.addElement(typename);
                    // .addAttribute("value", m.getValue().toString());
                    addStringElement(valueElem, "value", m.getValue().toString());
                    addChangeLog(m.getValue().getChangeLog(), valueElem);
                }
            }
            addChangeLog(a.getExperiment().getChangeLog(), experiment);

            addChangeLog(a.getChangeLog(), alt);
        }
        addChangeLog(p.getAlternativesDefinition().getChangeLog(), alternatives);

        // go-nogo - is created in the go-nogo step and need not exist
        if (p.getDecision() != null) {
            Element decision = projectNode.addElement("decision");
            addStringElement(decision, "reason", p.getDecision().getReason());
            addStringElement(decision, "actionNeeded", p.getDecision().getActionNeeded());
            decision.addElement("goDecision").addAttribute("value", p.getDecision().getDecision().name());
            addChangeLog(p.getDecision().getChangeLog(), decision);
        }

        // Evaluation
        Element evaluation = projectNode.addElement("evaluation");
        addStringElement(evaluation, "comment", p.getEvaluation().getComment());
        addChangeLog(p.getEvaluation().getChangeLog(), evaluation);

        // importance weighting
        Element importanceWeighting = projectNode.addElement("importanceWeighting");
        addStringElement(importanceWeighting, "comment", p.getImportanceWeighting().getComment());
        addChangeLog(p.getImportanceWeighting().getChangeLog(), importanceWeighting);

        // Recommendation
        Element recommendation = projectNode.addElement("recommendation");
        if (p.getRecommendation().getAlternative() != null) {
            recommendation.addAttribute("alternativeName", p.getRecommendation().getAlternative().getName());
        }
        addStringElement(recommendation, "reasoning", p.getRecommendation().getReasoning());
        addStringElement(recommendation, "effects", p.getRecommendation().getEffects());
        addChangeLog(p.getRecommendation().getChangeLog(), recommendation);

        // transformation
        Element trafo = projectNode.addElement("transformation");
        addStringElement(trafo, "comment", p.getTransformation().getComment());
        addChangeLog(p.getTransformation().getChangeLog(), trafo);

        // Objectivetree (including weights, evaluation values and
        // transformers)
        Element tree = projectNode.addElement("tree");
        tree.addAttribute("weightsInitialized", "" + p.getTree().isWeightsInitialized());
        if (p.getTree().getRoot() != null) {
            addSubTree(p.getTree().getRoot(), tree);
        }

        // add ExecutablePlanDefinition
        Element executablePlanDef = projectNode.addElement("executablePlan");
        ExecutablePlanDefinition executablePlanDefinition = p.getExecutablePlanDefinition();
        addStringElement(executablePlanDef, "objectPath", executablePlanDefinition.getObjectPath());
        addStringElement(executablePlanDef, "toolParameters", executablePlanDefinition.getToolParameters());
        addStringElement(executablePlanDef, "triggersConditions", executablePlanDefinition.getTriggersConditions());
        addStringElement(executablePlanDef, "validateQA", executablePlanDefinition.getValidateQA());
        addUpload(executablePlanDefinition.getT2flowExecutablePlan(), executablePlanDef, "workflow", addDigitalObjectData);
        addChangeLog(executablePlanDefinition.getChangeLog(), executablePlanDef);

        // Export generated preservation action plan
        addPreservationActionPlan(p.getPreservationActionPlan(), projectNode, addDigitalObjectData);

        // Plan definition
        Element planDef = projectNode.addElement("planDefinition");
        PlanDefinition pdef = p.getPlanDefinition();
        planDef.addAttribute("currency", pdef.getCurrency());
        addStringElement(planDef, "costsIG", pdef.getCostsIG());
        addStringElement(planDef, "costsPA", pdef.getCostsPA());
        addStringElement(planDef, "costsPE", pdef.getCostsPE());
        addStringElement(planDef, "costsQA", pdef.getCostsQA());
        addStringElement(planDef, "costsREI", pdef.getCostsREI());
        addStringElement(planDef, "costsRemarks", pdef.getCostsRemarks());
        addStringElement(planDef, "costsRM", pdef.getCostsRM());
        addStringElement(planDef, "costsTCO", pdef.getCostsTCO());

        addStringElement(planDef, "responsibleExecution", pdef.getResponsibleExecution());
        addStringElement(planDef, "responsibleMonitoring", pdef.getResponsibleMonitoring());

        triggers = planDef.addElement("triggers");
        if (pdef.getTriggers() != null) {
            addTrigger(pdef.getTriggers().getNewCollection(), triggers);
            addTrigger(pdef.getTriggers().getPeriodicReview(), triggers);
            addTrigger(pdef.getTriggers().getChangedEnvironment(), triggers);
            addTrigger(pdef.getTriggers().getChangedObjective(), triggers);
            addTrigger(pdef.getTriggers().getChangedCollectionProfile(), triggers);
        }

        addChangeLog(pdef.getChangeLog(), planDef);
    }

    /**
     * Adds the provided trigger to the parent element.
     *
     * @param t
     *            the trigger to add
     * @param parent
     *            the parent of the element to create
     * @return the newly created element or null if none was created
     */
    private Element addTrigger(Trigger t, Element parent) {
        Element trigger = null;
        if (t != null) {
            trigger = parent.addElement("trigger");
            trigger.addAttribute("type", t.getType().name());
            trigger.addAttribute("active", Boolean.toString(t.isActive()));
            trigger.addAttribute("description", t.getDescription());
        }
        return trigger;
    }

    /**
     * Long strings are stored as XML-elements, not as attributes. It is not
     * possible to add an element with value <code>null</code>, therefore this
     * has to be handled here: A new element is only added if there is a value
     * at all.
     *
     * @param parent
     *            the parent element of the element to create
     * @param name
     *            the name of the element to create
     * @param value
     *            the value of the element to create
     * @return the newly created element
     */
    private Element addStringElement(Element parent, String name, String value) {
        Element e = null;
        // &&(!"".equals(value)
        if (value != null) {
            e = parent.addElement(name);
            if (!"".equals(value)) {
                e.addText(value);
            }
        }
        return e;
    }

    public String exportTreeToFreemind(Plan plan) {
        return exportTreeToFreemind(plan.getTree().getRoot());
    }

    public String exportTreeToFreemind(TreeNode treeRoot) {
        Document doc = DocumentHelper.createDocument();
        Element root = doc.addElement("map");
        Namespace xsi = new Namespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");

        root.add(xsi);
        root.addAttribute("version", "0.8.1");

        root.addComment("To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net");
        addSubTreeFreemind(root, treeRoot);

        String xml = doc.asXML();
        // PlatoLogger.getLogger(ProjectExporter.class).debug(arg0)
        return xml;
    }

    private void addSubTreeFreemind(Element xmlElement, TreeNode node) {
        Element element = xmlElement.addElement("node");
        addFreemindAttributes(node, element);

        if (node.isLeaf()) {
            // add scale
            Leaf leaf = (Leaf) node;
            Scale scale = leaf.getScale();
            if (scale != null) {
                Element scaleElement = element.addElement("node");
                String restriction = "?";

                // restrictions: restrictedscale, ordinals -freestring

                if (scale instanceof FreeStringScale) {
                    restriction = "free text";
                } else if ((scale.getType() == ScaleType.ordinal || scale.getType() == ScaleType.restricted)
                    && !"".equals(((RestrictedScale) scale).getRestriction())) {
                    restriction = ((RestrictedScale) scale).getRestriction();
                } else {
                    restriction = scale.getUnit();
                }
                scaleElement.addAttribute("TEXT", restriction);
            }

        } else {
            // add children
            for (TreeNode child : node.getChildren()) {
                addSubTreeFreemind(element, child);
            }
        }
    }

    private void addFreemindAttributes(TreeNode node, Element element) {
        element.addAttribute("TEXT", node.getName());
        // TODO export weights? units? single? >> future.

        String mInfoUri = null;

        if (node.isLeaf()) {
            Leaf leaf = (Leaf) node;
            if (leaf.isMapped()) {
                mInfoUri = leaf.getMeasure().getUri();
            }
        }
        // add DESCRIPTION if existent
        if (((mInfoUri != null) && (!"".equals(mInfoUri)))
            || (node.getDescription() != null && !"".equals(node.getDescription()))) {
            Element hook = element.addElement("hook");
            hook.addAttribute("NAME", "accessories/plugins/NodeNote.properties");
            Element description = hook.addElement("text");

            String descr = "";
            // and measurement info

            if ((mInfoUri != null) && (!"".equals(mInfoUri))) {
                descr = "measureId=" + mInfoUri + "\n";
            }
            if (node.getDescription() != null) {
                descr = descr + node.getDescription();
            }
            description.setText(descr);
        }
    }

    /**
     * Adds the provided scale to the parent element.
     *
     * @param s
     *            the scale to add
     * @param parent
     *            the parent element of the element to add
     * @return the newly created element
     */
    private Element addScale(Scale s, Element parent) {
        Element scale = null;
        if (s != null) {
            String typename = deriveElementname(s.getClass());

            scale = parent.addElement(typename);
            // && (!"".equals(s.getUnit()
            if (s.getUnit() != null) {
                scale.addAttribute("unit", s.getUnit());
            }
            // scale.addAttribute("displayName", s.getDisplayName());

            if (s instanceof RestrictedScale) {
                scale.addAttribute("restriction", ((RestrictedScale) s).getRestriction());
            }
            addChangeLog(s.getChangeLog(), scale);
        }
        return scale;
    }

    /**
     * Adds a preservation action plan element to the provided parent if the
     * preservation action plan is defined.
     *
     * @param preservationActionPlan
     *            the preservation action plan to add
     * @param parent
     *            the parent element
     * @param addDigitalObjectData
     *            true if the data should be written, false otherwise
     * @return the newly created element or null
     * @throws PlanningException
     *             if an error occurred during creation
     */
    private Element addPreservationActionPlan(DigitalObject preservationActionPlan, Element parent,
        boolean addDigitalObjectData) throws PlanningException {

        Element preservationActionPlanElement = null;

        if (preservationActionPlan != null) {
            if (preservationActionPlan != null && preservationActionPlan.isDataExistent()) {
                if (!addDigitalObjectData) {
                    preservationActionPlanElement = parent.addElement("preservationActionPlan");
                    preservationActionPlanElement.setText(String.valueOf(preservationActionPlan.getId()));
                } else {
                    Document doc;
                    try {
                        doc = DocumentHelper
                            .parseText(new String(preservationActionPlan.getData().getData(), PlanXMLConstants.ENCODING));

                        if (doc.getRootElement().hasContent()) {
                            preservationActionPlanElement = doc.getRootElement();
                            parent.add(preservationActionPlanElement);
                        }
                    } catch (UnsupportedEncodingException e) {
                        log.error("Error parsing preservation action plan {}.", e.getMessage());
                        throw new PlanningException("Error parsing preservation action plan.", e);
                    } catch (DocumentException e) {
                        log.error("Error parsing preservation action plan {}.", e.getMessage());
                        throw new PlanningException("Error parsing preservation action plan.", e);
                    }
                }
            }
        }

        return preservationActionPlanElement;
    }
   
    private String encodeBase64(byte[] data) {
        return encoder.encodeAsString(data);
    }
}
TOP

Related Classes of eu.scape_project.planning.xml.ProjectExporter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.