/*******************************************************************************
* Copyright (c) 2006-2010 Vienna University of Technology,
* Department of Software Technology and Interactive Systems
*
* All rights reserved. This program and the accompanying
* materials are made available under the terms of the
* Apache License, Version 2.0 which accompanies
* this distribution, and is available at
* http://www.apache.org/licenses/LICENSE-2.0
*******************************************************************************/
package eu.planets_project.pp.plato.xml;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.digester.CallMethodRule;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.NodeCreateRule;
import org.apache.commons.logging.Log;
import org.dom4j.io.XMLWriter;
import org.jboss.annotation.ejb.cache.Cache;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.xml.sax.SAXException;
import eu.planets_project.pp.plato.action.interfaces.IProjectImport;
import eu.planets_project.pp.plato.model.Alternative;
import eu.planets_project.pp.plato.model.AlternativesDefinition;
import eu.planets_project.pp.plato.model.CollectionProfile;
import eu.planets_project.pp.plato.model.Decision;
import eu.planets_project.pp.plato.model.DetailedExperimentInfo;
import eu.planets_project.pp.plato.model.DigitalObject;
import eu.planets_project.pp.plato.model.Evaluation;
import eu.planets_project.pp.plato.model.ExecutablePlanDefinition;
import eu.planets_project.pp.plato.model.FormatInfo;
import eu.planets_project.pp.plato.model.ImportanceWeighting;
import eu.planets_project.pp.plato.model.Parameter;
import eu.planets_project.pp.plato.model.Plan;
import eu.planets_project.pp.plato.model.PlanDefinition;
import eu.planets_project.pp.plato.model.PlanProperties;
import eu.planets_project.pp.plato.model.PlanState;
import eu.planets_project.pp.plato.model.Policy;
import eu.planets_project.pp.plato.model.PolicyNode;
import eu.planets_project.pp.plato.model.PreservationActionDefinition;
import eu.planets_project.pp.plato.model.ProjectBasis;
import eu.planets_project.pp.plato.model.RequirementsDefinition;
import eu.planets_project.pp.plato.model.ResourceDescription;
import eu.planets_project.pp.plato.model.SampleObject;
import eu.planets_project.pp.plato.model.SampleRecordsDefinition;
import eu.planets_project.pp.plato.model.Transformation;
import eu.planets_project.pp.plato.model.TriggerDefinition;
import eu.planets_project.pp.plato.model.Values;
import eu.planets_project.pp.plato.model.XcdlDescription;
import eu.planets_project.pp.plato.model.measurement.MeasurableProperty;
import eu.planets_project.pp.plato.model.measurement.Measurement;
import eu.planets_project.pp.plato.model.measurement.MeasurementInfo;
import eu.planets_project.pp.plato.model.measurement.Metric;
import eu.planets_project.pp.plato.model.scales.BooleanScale;
import eu.planets_project.pp.plato.model.scales.FloatRangeScale;
import eu.planets_project.pp.plato.model.scales.FloatScale;
import eu.planets_project.pp.plato.model.scales.FreeStringScale;
import eu.planets_project.pp.plato.model.scales.IntRangeScale;
import eu.planets_project.pp.plato.model.scales.IntegerScale;
import eu.planets_project.pp.plato.model.scales.OrdinalScale;
import eu.planets_project.pp.plato.model.scales.PositiveFloatScale;
import eu.planets_project.pp.plato.model.scales.PositiveIntegerScale;
import eu.planets_project.pp.plato.model.scales.YanScale;
import eu.planets_project.pp.plato.model.transform.NumericTransformer;
import eu.planets_project.pp.plato.model.transform.OrdinalTransformer;
import eu.planets_project.pp.plato.model.tree.Leaf;
import eu.planets_project.pp.plato.model.tree.Node;
import eu.planets_project.pp.plato.model.tree.ObjectiveTree;
import eu.planets_project.pp.plato.model.tree.PolicyTree;
import eu.planets_project.pp.plato.model.tree.TemplateTree;
import eu.planets_project.pp.plato.model.tree.TreeNode;
import eu.planets_project.pp.plato.model.values.BooleanValue;
import eu.planets_project.pp.plato.model.values.FloatRangeValue;
import eu.planets_project.pp.plato.model.values.FloatValue;
import eu.planets_project.pp.plato.model.values.FreeStringValue;
import eu.planets_project.pp.plato.model.values.IntRangeValue;
import eu.planets_project.pp.plato.model.values.IntegerValue;
import eu.planets_project.pp.plato.model.values.OrdinalValue;
import eu.planets_project.pp.plato.model.values.PositiveFloatValue;
import eu.planets_project.pp.plato.model.values.PositiveIntegerValue;
import eu.planets_project.pp.plato.model.values.YanValue;
import eu.planets_project.pp.plato.services.characterisation.jhove.JHoveAdaptor;
import eu.planets_project.pp.plato.util.FileUtils;
import eu.planets_project.pp.plato.util.OS;
import eu.planets_project.pp.plato.util.PlatoLogger;
import eu.planets_project.pp.plato.xml.plato.BinaryDataWrapper;
import eu.planets_project.pp.plato.xml.plato.ChangeLogFactory;
import eu.planets_project.pp.plato.xml.plato.ExperimentWrapper;
import eu.planets_project.pp.plato.xml.plato.GoDecisionFactory;
import eu.planets_project.pp.plato.xml.plato.NodeContentWrapper;
import eu.planets_project.pp.plato.xml.plato.OrdinalTransformerMappingFactory;
import eu.planets_project.pp.plato.xml.plato.RecommendationWrapper;
import eu.planets_project.pp.plato.xml.plato.SampleAggregationModeFactory;
import eu.planets_project.pp.plato.xml.plato.TransformationModeFactory;
import eu.planets_project.pp.plato.xml.plato.TriggerFactory;
@Stateful
@Scope(ScopeType.SESSION)
@Name("projectImport")
@Cache(org.jboss.ejb3.cache.NoPassivationCache.class)
public class ProjectImporter implements IProjectImport, Serializable {
/**
*
*/
private static final long serialVersionUID = 4909854324732570490L;
private static Log log = PlatoLogger.getLogger(ProjectImporter.class);
/**
* Imports the given file. This function is only used for test purposes in
* {@link #main(String[])}
*/
public List<Plan> importProjects(String file) throws IOException,
SAXException {
FileInputStream in = new FileInputStream(file);
return importProjects(in);
}
public int importAllProjectsFromDir(File dir) {
int count = 0;
for (String s : dir.list()) {
log.debug("importing file: " + s);
try {
String file = dir.getAbsolutePath() + File.separator + s;
for (Plan p : importProjects(file)) {
em.persist(p);
count++;
}
} catch (IOException e) {
log.error("IMPORT FAILED: could not import file " + s, e);
} catch (SAXException e) {
log.error("IMPORT FAILED: could not import file " + s, e);
}
}
return count;
}
private List<Plan> plans;
private List<TemplateTree> templates;
private String fileVersion;
private List<String> appliedTransformations;
@In
EntityManager em;
/**
* can be used to set data for a specific ByteStream, for example for
* two-pass XML import. but: NOT USED AT THE MOMENT, and probably will not
* be needed soon!
*
* @param byteStreamID
* @param data
* private void insertData(int byteStreamID, byte[] data) {
* ByteStream b = em.find(ByteStream.class, byteStreamID); if (b
* == null) {
* log.error("INCONSISTENCY: bytestream with ID "+byteStreamID
* +" not found!"); return; } b.setData(data); em.persist(b);
* em.flush(); b = null; em.clear(); }
*/
/**
* Used by the digester every time a project has been parsed.
*
* @param p
*/
public void setProject(Plan p) {
plans.add(p);
}
/**
* Used by the digester every time a template has been parsed.
*
* @param t
*/
public void setTemplate(TemplateTree t) {
templates.add(t);
}
@Destroy
@Remove
public void destroy() {
}
/**
* Detect the version of the given XML representation of plans. If the
* version of the XML representation is not up to date, necessary
* transformations are applied.
*
* @param importData
* @return null if the transformation fails, otherwise an up to date XML
* representation
* @throws IOException
* if parsing the XML representation fails
* @throws SAXException
* if parsing the XML representation fails
*/
public String getCurrentVersionData(InputStream in, String tempPath) throws IOException,
SAXException {
appliedTransformations = new ArrayList<String>();
String originalFile = tempPath + "_original.xml";
OutputStream out = new BufferedOutputStream(new FileOutputStream(originalFile));
FileUtils.writeToFile(in, out);
out.close();
/** check for the version of the file **/
fileVersion = "xxx";
Digester d = new Digester();
d.setValidating(false);
StrictErrorHandler errorHandler = new StrictErrorHandler();
d.setErrorHandler(errorHandler);
d.push(this);
// to read the version we have to support all versions:
d.addSetProperties("*/projects", "version", "fileVersion");
// manually migrated projects may have the file version in the node
// projects/project
d.addSetProperties("*/projects/project", "version", "fileVersion");
// pre V1.3 version info was stored in the project node
d.addSetProperties("*/project", "version", "fileVersion");
// since V1.9 the root node is plans:
d.addSetProperties("*/plans", "version", "fileVersion");
InputStream inV = new FileInputStream(originalFile);
d.parse(inV);
inV.close();
/** this could be more sophisticated, but for now this is enough **/
String version = "1.0";
if (fileVersion != null) {
version = fileVersion;
}
String fileTo = originalFile;
String fileFrom = originalFile;
boolean success = true;
if ("xxx".equals(version)) {
fileFrom = fileTo;
fileTo = fileFrom + "_V1.3.xml";
/** this is an old export file, transform it to the 1.3 schema **/
success = transformXmlData(fileFrom, fileTo, "data/xslt/Vxxx-to-V1.3.xsl");
appliedTransformations.add("Vxxx-to-V1.3.xsl");
version = "1.3";
}
if (success && "1.3".equals(version)) {
fileFrom = fileTo;
fileTo = fileFrom + "_V1.9.xml";
success = transformXmlData(fileFrom, fileTo, "data/xslt/V1.3-to-V1.9.xsl");
appliedTransformations.add("V1.3-to-V1.9.xsl");
version = "1.9";
}
// with release of Plato 2.0 and its schema ProjectExporter creates
// documents with version 2.0
if (success && "1.9".equals(version)) {
version = "2.0";
}
if (success && "2.0".equals(version)) {
// transform the document to version 2.1
fileFrom = fileTo;
fileTo = fileFrom + "_V2.1.xml";
success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.0-to-V2.1.xsl");
appliedTransformations.add("V2.0-to-V2.1.xsl");
version = "2.1";
}
if (success && "2.1".equals(version)) {
// transform the document to version 2.1.2
fileFrom = fileTo;
fileTo = fileFrom + "_V2.1.2.xml";
success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.1-to-V2.1.2.xsl");
appliedTransformations.add("V2.1-to-V2.1.2.xsl");
version = "2.1.2";
}
if (success && "2.1.1".equals(version)) {
// transform the document to version 2.1.2
fileFrom = fileTo;
fileTo = fileFrom + "_V2.1.2.xml";
success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.1.1-to-V2.1.2.xsl");
appliedTransformations.add("V2.1.1-to-V2.1.2.xsl");
version = "2.1.2";
}
if (success && "2.1.2".equals(version)) {
// transform the document to version 3.0.0
fileFrom = fileTo;
fileTo = fileFrom + "_V3.0.0.xml";
success = transformXmlData(fileFrom, fileTo, "data/xslt/V2.1.2-to-V3.0.0.xsl");
appliedTransformations.add("V2.1.2-to-V3.0.0.xsl");
version = "3.0.0";
}
if (success) {
return fileTo;
} else {
return null;
}
}
public boolean transformXmlData(String fromFile, String toFile, String xslFile)
throws IOException {
try {
InputStream xsl = Thread.currentThread().getContextClassLoader().getResourceAsStream(xslFile);
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory
.newTransformer(new StreamSource(xsl));// schemaUrl.openStream()
OutputStream transformedOut = new FileOutputStream(toFile);
Result outputTarget = new StreamResult(transformedOut);
Source xmlSource = new StreamSource(new FileInputStream(fromFile));
transformer.transform(xmlSource, outputTarget);
transformedOut.close();
return true;
} catch (TransformerConfigurationException e) {
log.debug(e);
} catch (TransformerFactoryConfigurationError e) {
log.debug(e);
} catch (TransformerException e) {
log.debug(e);
}
return false;
}
/**
* This method takes a template xml and stores the templates in the template library. The 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>
*
* We go through the templates //templates/template/node and store them in the respective template library, in this
* case 'Public Fragments'
*
* @param xml
* @throws SAXException
* @throws IOException
*/
public void storeTemplatesInLibrary(byte[] xml) throws SAXException, IOException {
List<TemplateTree> templates = importTemplates(xml);
/*
* store all templates
*/
for (TemplateTree template : templates) {
// we get the template tree ("Public Templates") from the database
TemplateTree tdb;
try {
tdb = (TemplateTree) em.createQuery("select n from TemplateTree n where name = :name")
.setParameter("name", template.getName())
.getSingleResult();
} catch(NoResultException e) {
tdb = new TemplateTree(template.getName(), null);
}
if (tdb != null) {
// we get the templates and add them to the tree
// and store them
for (TreeNode n : template.getRoot().getChildren()) {
tdb.getRoot().addChild(n);
em.persist(n);
}
em.persist(em.merge(tdb));
em.flush();
}
}
}
/**
* Imports the XML representation of templates.
*
* @return list of read templates.
*/
public List<TemplateTree> importTemplates(byte[] in) throws IOException,
SAXException {
Digester digester = new Digester();
//digester.setValidating(true);
StrictErrorHandler errorHandler = new StrictErrorHandler();
digester.setErrorHandler(errorHandler);
// At the moment XML files for template tree's are only used internally,
// later we will define a schema and use it also for validation
digester.push(this);
digester.addObjectCreate("*/template", TemplateTree.class);
digester.addSetProperties("*/template");
digester.addSetRoot("*/template", "setTemplate");
// digester.addSetNext("*/template/name", "setName");
// digester.addSetNext("*/template/owner", "setOwner");
ProjectImporter.addTreeParsingRulesToDigester(digester);
digester.addObjectCreate("*/template/node", Node.class);
digester.addSetProperties("*/template/node");
digester.addSetNext("*/template/node", "addChild");
digester.setUseContextClassLoader(true);
this.templates = new ArrayList<TemplateTree>();
digester.parse(new ByteArrayInputStream(in));
/*
* for (TemplateTree t : this.templates) { log.info(t.getName() +
* t.getOwner()); }
*/
return this.templates;
}
/**
* Imports the XML representation of plans from the given inputstream.
*
* @return list of read plans
*/
public List<Plan> importProjects(InputStream in) throws IOException, SAXException {
String tempPath = OS.getTmpPath() + "import_xml" + System.currentTimeMillis() + "/";
File tempDir = new File(tempPath);
tempDir.mkdirs();
try {
String currentVersionFile = getCurrentVersionData(in, tempPath);
if (currentVersionFile == null) {
log.error("Failed to migrate plans.");
return this.plans;
}
Digester digester = new Digester();
// digester.setValidating(true);
StrictErrorHandler errorHandler = new StrictErrorHandler();
digester.setErrorHandler(errorHandler);
digester.setNamespaceAware(true);
// digester.setSchemaLanguage("http://www.w3.org/2001/XMLSchema");
// digester.setSchema("http://localhost:8080/plato/schema/plato-2.1.xsd");
/*
* It is NOT sufficient to use setValidating(true) and digester.setSchema("data/schemas/plato.xsd")!
* the following parameters have to be set and a special error handler is necessary
*/
try {
digester.setFeature("http://xml.org/sax/features/validation", true);
digester.setFeature("http://apache.org/xml/features/validation/schema",true);
//
digester.setFeature("http://xml.org/sax/features/namespaces", true);
// digester.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true);
/*
* And provide the relative path to the xsd-schema:
*/
digester.setProperty(
"http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
URL platoSchema = Thread.currentThread().getContextClassLoader().getResource("data/schemas/plato-3.0.xsd");
URL wdtSchema = Thread.currentThread().getContextClassLoader().getResource("data/schemas/planets_wdt-1.0.xsd");
digester.setProperty(
"http://apache.org/xml/properties/schema/external-schemaLocation",
"http://www.planets-project.eu/plato " + platoSchema + " http://www.planets-project.eu/wdt " + wdtSchema);
//http://localhost:8080/plato/schema/planets_wdt-1.0.xsd
} catch (ParserConfigurationException e) {
log.debug("Cannot import XML file: Configuration of parser failed.", e);
throw new SAXException("Cannot import XML file: Configuration of parser failed.");
}
digester.push(this);
// start with a new file
digester.addObjectCreate("*/plan", Plan.class);
digester.addSetProperties("*/plan");
digester.addSetRoot("*/plan", "setProject");
digester.addFactoryCreate("*/changelog", ChangeLogFactory.class);
digester.addSetNext("*/changelog", "setChangeLog");
digester.addObjectCreate("*/plan/state", PlanState.class);
digester.addSetProperties("*/plan/state");
digester.addSetNext("*/plan/state", "setState");
digester.addObjectCreate("*/plan/properties", PlanProperties.class);
digester.addSetProperties("*/plan/properties");
digester.addSetNext("*/plan/properties", "setPlanProperties");
digester.addCallMethod("*/plan/properties/description", "setDescription", 0);
digester.addCallMethod("*/plan/properties/owner", "setOwner", 0);
addCreateUpload(digester, "*/plan/properties/report", "setReportUpload", DigitalObject.class);
digester.addObjectCreate("*/plan/basis", ProjectBasis.class);
digester.addSetProperties("*/plan/basis");
digester.addSetNext("*/plan/basis", "setProjectBasis");
digester.addCallMethod("*/plan/basis/applyingPolicies", "setApplyingPolicies", 0);
digester.addCallMethod("*/plan/basis/designatedCommunity", "setDesignatedCommunity", 0);
digester.addCallMethod("*/plan/basis/mandate", "setMandate", 0);
digester.addCallMethod("*/plan/basis/documentTypes", "setDocumentTypes", 0);
digester.addCallMethod("*/plan/basis/identificationCode", "setIdentificationCode", 0);
digester.addCallMethod("*/plan/basis/organisationalProcedures", "setOrganisationalProcedures", 0);
digester.addCallMethod("*/plan/basis/planningPurpose", "setPlanningPurpose", 0);
digester.addCallMethod("*/plan/basis/planRelations", "setPlanRelations", 0);
digester.addCallMethod("*/plan/basis/preservationRights", "setPreservationRights", 0);
digester.addCallMethod("*/plan/basis/referenceToAgreements", "setReferenceToAgreements", 0);
// define common rule for triggers, for all */triggers/...!
// also used for PlanDefinition
digester.addObjectCreate("*/triggers", TriggerDefinition.class);
digester.addSetNext("*/triggers","setTriggers");
// every time a */triggers/trigger is encountered:
digester.addFactoryCreate("*/triggers/trigger",TriggerFactory.class);
digester.addSetNext("*/triggers/trigger","setTrigger");
//
// Policy Tree
//
digester.addObjectCreate("*/plan/basis/policyTree", PolicyTree.class);
digester.addSetProperties("*/plan/basis/policyTree");
digester.addSetNext("*/plan/basis/policyTree", "setPolicyTree");
digester.addObjectCreate("*/plan/basis/policyTree/policyNode", PolicyNode.class);
digester.addSetProperties("*/plan/basis/policyTree/policyNode");
digester.addSetNext("*/plan/basis/policyTree/policyNode", "setRoot");
digester.addObjectCreate("*/policyNode/policyNode", PolicyNode.class);
digester.addSetProperties("*/policyNode/policyNode");
digester.addSetNext("*/policyNode/policyNode", "addChild");
digester.addObjectCreate("*/policyNode/policy", Policy.class);
digester.addSetProperties("*/policyNode/policy");
digester.addSetNext("*/policyNode/policy", "addChild");
//
// Sample Records
//
digester.addObjectCreate("*/plan/sampleRecords", SampleRecordsDefinition.class);
digester.addSetProperties("*/plan/sampleRecords");
digester.addSetNext("*/plan/sampleRecords", "setSampleRecordsDefinition");
digester.addCallMethod("*/plan/sampleRecords/samplesDescription", "setSamplesDescription", 0);
// - records
digester.addObjectCreate("*/record", SampleObject.class);
digester.addSetProperties("*/record");
digester.addSetNext("*/record", "addRecord");
digester.addCallMethod("*/record/description", "setDescription", 0);
digester.addCallMethod("*/record/originalTechnicalEnvironment", "setOriginalTechnicalEnvironment", 0);
digester.addObjectCreate("*/record/data", BinaryDataWrapper.class);
digester.addSetTop("*/record/data", "setData");
digester.addCallMethod("*/record/data", "setFromBase64Encoded", 0);
// set up an general rule for all jhove strings!
digester.addObjectCreate("*/jhoveXML", BinaryDataWrapper.class);
digester.addSetTop("*/jhoveXML", "setString");
digester.addCallMethod("*/jhoveXML", "setFromBase64Encoded", 0);
digester.addCallMethod("*/jhoveXML", "setMethodName", 1, new String[]{"java.lang.String"});
digester.addObjectParam("*/jhoveXML", 0, "setJhoveXMLString");
// set up general rule for all fitsXMLs
digester.addObjectCreate("*/fitsXML", BinaryDataWrapper.class);
digester.addSetTop("*/fitsXML", "setString");
digester.addCallMethod("*/fitsXML", "setFromBase64Encoded", 0);
digester.addCallMethod("*/fitsXML", "setMethodName", 1, new String[]{"java.lang.String"});
digester.addObjectParam("*/fitsXML", 0, "setFitsXMLString");
digester.addObjectCreate("*/record/formatInfo", FormatInfo.class);
digester.addSetProperties("*/record/formatInfo");
digester.addSetNext("*/record/formatInfo", "setFormatInfo");
addCreateUpload(digester, "*/record/xcdlDescription", "setXcdlDescription", XcdlDescription.class);
// - collection profile
digester.addObjectCreate("*/plan/sampleRecords/collectionProfile", CollectionProfile.class);
digester.addSetProperties("*/plan/sampleRecords/collectionProfile");
digester.addSetNext("*/plan/sampleRecords/collectionProfile", "setCollectionProfile");
digester.addCallMethod("*/plan/sampleRecords/collectionProfile/collectionID", "setCollectionID", 0);
digester.addCallMethod("*/plan/sampleRecords/collectionProfile/description", "setDescription", 0);
digester.addCallMethod("*/plan/sampleRecords/collectionProfile/numberOfObjects", "setNumberOfObjects", 0);
digester.addCallMethod("*/plan/sampleRecords/collectionProfile/typeOfObjects", "setTypeOfObjects", 0);
digester.addCallMethod("*/plan/sampleRecords/collectionProfile/expectedGrowthRate", "setExpectedGrowthRate", 0);
digester.addCallMethod("*/plan/sampleRecords/collectionProfile/retentionPeriod", "setRetentionPeriod", 0);
// requirements definition
digester.addObjectCreate("*/plan/requirementsDefinition", RequirementsDefinition.class);
digester.addSetProperties("*/plan/requirementsDefinition");
digester.addSetNext("*/plan/requirementsDefinition", "setRequirementsDefinition");
digester.addCallMethod("*/plan/requirementsDefinition/description", "setDescription", 0);
// - uploads
digester.addObjectCreate("*/plan/requirementsDefinition/uploads", ArrayList.class);
digester.addSetNext("*/plan/requirementsDefinition/uploads", "setUploads");
addCreateUpload(digester, "*/plan/requirementsDefinition/uploads/upload", "add", DigitalObject.class);
// alternatives
digester.addObjectCreate("*/plan/alternatives", AlternativesDefinition.class);
digester.addSetProperties("*/plan/alternatives");
digester.addCallMethod("*/plan/alternatives/description", "setDescription", 0);
digester.addSetNext("*/plan/alternatives", "setAlternativesDefinition");
digester.addObjectCreate("*/plan/alternatives/alternative", Alternative.class);
digester.addSetProperties("*/plan/alternatives/alternative");
digester.addSetNext("*/plan/alternatives/alternative", "addAlternative");
// - action
digester.addObjectCreate("*/plan/alternatives/alternative/action", PreservationActionDefinition.class);
digester.addSetProperties("*/plan/alternatives/alternative/action");
digester.addBeanPropertySetter("*/plan/alternatives/alternative/action/descriptor");
digester.addBeanPropertySetter("*/plan/alternatives/alternative/action/parameterInfo");
digester.addSetNext("*/plan/alternatives/alternative/action", "setAction");
digester.addCallMethod("*/plan/alternatives/alternative/description", "setDescription", 0);
// - - params
digester.addObjectCreate("*/plan/alternatives/alternative/action/params", LinkedList.class);
digester.addSetNext("*/plan/alternatives/alternative/action/params", "setParams");
digester.addObjectCreate("*/plan/alternatives/alternative/action/params/param", Parameter.class);
digester.addSetProperties("*/plan/alternatives/alternative/action/params/param");
digester.addSetNext("*/plan/alternatives/alternative/action/params/param", "add");
// - resource description
digester.addObjectCreate("*/resourceDescription", ResourceDescription.class);
digester.addSetProperties("*/resourceDescription");
digester.addSetNext("*/resourceDescription", "setResourceDescription");
digester.addCallMethod("*/resourceDescription/configSettings", "setConfigSettings", 0);
digester.addCallMethod("*/resourceDescription/necessaryResources", "setNecessaryResources", 0);
digester.addCallMethod("*/resourceDescription/reasonForConsidering", "setReasonForConsidering", 0);
// - experiment
digester.addObjectCreate("*/experiment", ExperimentWrapper.class);
digester.addSetProperties("*/experiment");
digester.addSetNext("*/experiment", "setExperiment");
digester.addCallMethod("*/experiment/description", "setDescription", 0);
digester.addCallMethod("*/experiment/settings", "setSettings", 0);
addCreateUpload(digester, "*/experiment/results/result", null, DigitalObject.class);
addCreateUpload(digester, "*/result/xcdlDescription", "setXcdlDescription", XcdlDescription.class);
// call function addUpload of ExperimentWrapper
CallMethodRule r = new CallMethodRule(1, "addResult", 2); //method with two params
// every time */experiment/uploads/upload is encountered
digester.addRule("*/experiment/results/result", r);
// use attribute "key" as first param
digester.addCallParam("*/experiment/results/result", 0 , "key");
// and the object on stack (DigitalObject) as the second
digester.addCallParam("*/experiment/results/result",1,true);
// addCreateUpload(digester, "*/experiment/xcdlDescriptions/xcdlDescription", null, XcdlDescription.class);
// // call function addXcdlDescription of ExperimentWrapper
// r = new CallMethodRule(1, "addXcdlDescription", 2); //method with two params
// // every time */experiment/xcdlDescriptions/xcdlDescription is encountered
// digester.addRule("*/experiment/xcdlDescriptions/xcdlDescription", r);
// // use attribute "key" as first param
// digester.addCallParam("*/experiment/xcdlDescriptions/xcdlDescription", 0 , "key");
// // and the object on stack (DigitalObject) as the second
// digester.addCallParam("*/experiment/xcdlDescriptions/xcdlDescription",1,true);
digester.addObjectCreate("*/experiment/detailedInfos/detailedInfo", DetailedExperimentInfo.class);
digester.addSetProperties("*/experiment/detailedInfos/detailedInfo");
digester.addBeanPropertySetter("*/experiment/detailedInfos/detailedInfo/programOutput");
digester.addBeanPropertySetter("*/experiment/detailedInfos/detailedInfo/cpr");
// call function "addDetailedInfo" of ExperimentWrapper
r = new CallMethodRule(1, "addDetailedInfo", 2); //method with two params
// every time */experiment/detailedInfos/detailedInfo is encountered
digester.addRule("*/experiment/detailedInfos/detailedInfo", r);
// use attribute "key" as first param
digester.addCallParam("*/experiment/detailedInfos/detailedInfo", 0 , "key");
// and the object on stack as second parameter
digester.addCallParam("*/experiment/detailedInfos/detailedInfo",1,true);
// read contained measurements:
digester.addObjectCreate("*/detailedInfo/measurements/measurement", Measurement.class);
digester.addSetNext("*/detailedInfo/measurements/measurement", "put");
// values are defined with wild-cards, and therefore set automatically
digester.addObjectCreate("*/measurement/property", MeasurableProperty.class);
digester.addSetProperties("*/measurement/property");
digester.addSetNext("*/measurement/property", "setProperty");
// scales are defined with wild-cards, and therefore set automatically
/*
* for each value type a set of rules
* because of FreeStringValue we need to store the value as XML-element
* instead of an attribute
* naming them "ResultValues" wasn't nice too
*/
addCreateValue(digester, BooleanValue.class, "setValue");
addCreateValue(digester, FloatRangeValue.class, "setValue");
addCreateValue(digester, IntegerValue.class, "setValue");
addCreateValue(digester, IntRangeValue.class, "setValue");
addCreateValue(digester, OrdinalValue.class, "setValue");
addCreateValue(digester, PositiveFloatValue.class, "setValue");
addCreateValue(digester, PositiveIntegerValue.class, "setValue");
addCreateValue(digester, YanValue.class, "setValue");
addCreateValue(digester, FreeStringValue.class, "setValue");
// go no go decision
digester.addObjectCreate("*/plan/decision", Decision.class);
digester.addSetProperties("*/plan/decision");
digester.addSetNext("*/plan/decision", "setDecision");
digester.addCallMethod("*/plan/decision/actionNeeded", "setActionNeeded", 0);
digester.addCallMethod("*/plan/decision/reason", "setReason", 0);
digester.addFactoryCreate("*/plan/decision/goDecision", GoDecisionFactory.class);
digester.addSetNext("*/plan/decision/goDecision", "setDecision");
// evaluation
digester.addObjectCreate("*/plan/evaluation", Evaluation.class);
digester.addSetProperties("*/plan/evaluation");
digester.addSetNext("*/plan/evaluation", "setEvaluation");
digester.addCallMethod("*/plan/evaluation/comment", "setComment", 0);
// importance weighting
digester.addObjectCreate("*/plan/importanceWeighting", ImportanceWeighting.class);
digester.addSetProperties("*/plan/importanceWeighting");
digester.addSetNext("*/plan/importanceWeighting", "setImportanceWeighting");
digester.addCallMethod("*/plan/importanceWeighting/comment", "setComment", 0);
// recommendation
digester.addObjectCreate("*/plan/recommendation", RecommendationWrapper.class);
digester.addSetProperties("*/plan/recommendation");
digester.addSetNext("*/plan/recommendation", "setRecommendation");
digester.addCallMethod("*/plan/recommendation/reasoning", "setReasoning", 0);
digester.addCallMethod("*/plan/recommendation/effects", "setEffects", 0);
// transformation
digester.addObjectCreate("*/plan/transformation", Transformation.class);
digester.addSetProperties("*/plan/transformation");
digester.addSetNext("*/plan/transformation", "setTransformation");
digester.addCallMethod("*/plan/transformation/comment", "setComment", 0);
// Tree
/* Some rules for tree parsing are necessary for importing templates too,
* that's why they are added by this static method. */
ProjectImporter.addTreeParsingRulesToDigester(digester);
digester.addObjectCreate("*/leaf/evaluation", HashMap.class);
digester.addSetNext("*/leaf/evaluation", "setValueMap");
/*
* The valueMap has an entry for each (considered) alternative ...
* and for each alternative there is a list of values, one per SampleObject.
* Note: The digester uses a stack, therefore the rule to put the list of values to the valueMap
* must be added after the rule for adding the values to the list.
*/
/*
* 2. and for each alternative there is a list of values, one per SampleObject
*/
digester.addObjectCreate("*/leaf/evaluation/alternative", Values.class);
digester.addCallMethod("*/leaf/evaluation/alternative/comment", "setComment", 0);
/*
* for each result-type a set of rules
* they are added to the valueMap by the rules above
*/
addCreateResultValue(digester, BooleanValue.class);
addCreateResultValue(digester, FloatValue.class);
addCreateResultValue(digester, FloatRangeValue.class);
addCreateResultValue(digester, IntegerValue.class);
addCreateResultValue(digester, IntRangeValue.class);
addCreateResultValue(digester, OrdinalValue.class);
addCreateResultValue(digester, PositiveFloatValue.class);
addCreateResultValue(digester, PositiveIntegerValue.class);
addCreateResultValue(digester, YanValue.class);
addCreateResultValue(digester, FreeStringValue.class);
/*
* 1. The valueMap has an entry for each (considered) alternative ...
*/
// call put of the ValueMap (HashMap)
r = new CallMethodRule(1, "put", 2);
digester.addRule("*/leaf/evaluation/alternative", r);
digester.addCallParam("*/leaf/evaluation/alternative", 0 , "key");
digester.addCallParam("*/leaf/evaluation/alternative",1,true);
// digester.addObjectCreate("*/plan/executablePlan/planWorkflow", ExecutablePlanContentWrapper.class);
// digester.addSetProperties("*/plan/executablePlan/planWorkflow");
// digester.addSetNext("*/plan/executablePlan/planWorkflow", "setRecommendation");
// Executable plan definition
digester.addObjectCreate("*/plan/executablePlan", ExecutablePlanDefinition.class);
digester.addSetProperties("*/plan/executablePlan");
digester.addSetNext("*/plan/executablePlan", "setExecutablePlanDefinition");
//
// Import Planets executable plan if present
//
try {
// object-create rules are called at the beginning element-tags, in the same order as defined
// first create the wrapper
digester.addObjectCreate("*/plan/executablePlan/planWorkflow", NodeContentWrapper.class);
// then an element for workflowConf
digester.addRule("*/plan/executablePlan/planWorkflow/workflowConf", new NodeCreateRule());
// CallMethod and SetNext rules are called at closing element-tags, (last in - first out!)
CallMethodRule rr = new CallMethodRule(1, "setNodeContent", 2);
digester.addRule("*/plan/executablePlan/planWorkflow/workflowConf", rr);
// right below the wrapper is an instance of ExecutablePlanDefinition
digester.addCallParam("*/plan/executablePlan/planWorkflow/workflowConf", 0 , 1);
// provide the name of the setter method
digester.addObjectParam("*/plan/executablePlan/planWorkflow/workflowConf", 1, "setExecutablePlan");
// the generated node is not accessible as CallParam (why?!?), but available for addSetNext
digester.addSetNext("*/plan/executablePlan/planWorkflow/workflowConf", "setNode");
} catch (ParserConfigurationException e) {
PlatoLogger.getLogger(this.getClass()).error(e.getMessage(),e);
}
//
// Import EPrints executable plan if present
//
try {
digester.addObjectCreate("*/plan/executablePlan/eprintsPlan", NodeContentWrapper.class);
// then an element for workflowConf
digester.addRule("*/plan/executablePlan/eprintsPlan", new NodeCreateRule());
CallMethodRule rr2 = new CallMethodRule(1, "setNodeContentEPrintsPlan", 2);
digester.addRule("*/plan/executablePlan/eprintsPlan", rr2);
// right below the wrapper is an instance of ExecutablePlanDefinition
digester.addCallParam("*/plan/executablePlan/eprintsPlan", 0 , 1);
// provide the name of the setter method
digester.addObjectParam("*/plan/executablePlan/eprintsPlan", 1, "setEprintsExecutablePlan");
digester.addSetNext("*/plan/executablePlan/eprintsPlan", "setNode");
} catch (ParserConfigurationException e) {
PlatoLogger.getLogger(this.getClass()).error(e.getMessage(),e);
}
digester.addCallMethod("*/plan/executablePlan/objectPath", "setObjectPath", 0);
digester.addCallMethod("*/plan/executablePlan/toolParameters", "setToolParameters", 0);
digester.addCallMethod("*/plan/executablePlan/triggersConditions", "setTriggersConditions", 0);
digester.addCallMethod("*/plan/executablePlan/validateQA", "setValidateQA", 0);
// Plan definition
digester.addObjectCreate("*/plan/planDefinition", PlanDefinition.class);
digester.addSetProperties("*/plan/planDefinition");
digester.addSetNext("*/plan/planDefinition", "setPlanDefinition");
digester.addCallMethod("*/plan/planDefinition/costsIG", "setCostsIG", 0);
digester.addCallMethod("*/plan/planDefinition/costsPA", "setCostsPA", 0);
digester.addCallMethod("*/plan/planDefinition/costsPE", "setCostsPE", 0);
digester.addCallMethod("*/plan/planDefinition/costsQA", "setCostsQA", 0);
digester.addCallMethod("*/plan/planDefinition/costsREI", "setCostsREI", 0);
digester.addCallMethod("*/plan/planDefinition/costsRemarks", "setCostsRemarks", 0);
digester.addCallMethod("*/plan/planDefinition/costsRM", "setCostsRM", 0);
digester.addCallMethod("*/plan/planDefinition/costsTCO", "setCostsTCO", 0);
digester.addCallMethod("*/plan/planDefinition/responsibleExecution", "setResponsibleExecution", 0);
digester.addCallMethod("*/plan/planDefinition/responsibleMonitoring", "setResponsibleMonitoring", 0);
digester.addObjectCreate("*/plan/planDefinition/triggers", TriggerDefinition.class);
digester.addSetNext("*/plan/planDefinition/triggers","setTriggers");
// every time a */plan/basis/triggers/trigger is encountered:
digester.addFactoryCreate("*/plan/planDefinition/triggers/trigger",TriggerFactory.class);
digester.addSetNext("*/plan/planDefinition/triggers/trigger","setTrigger");
digester.setUseContextClassLoader(true);
this.plans = new ArrayList<Plan>();
// finally parse the XML representation with all created rules
digester.parse(new FileInputStream(currentVersionFile));
for (Plan plan : plans) {
String projectName = plan.getPlanProperties().getName();
if ((projectName != null) &&
(!"".equals(projectName))) {
/*
* establish links from values to scales
*/
plan.getTree().initValues(
plan.getAlternativesDefinition().getConsideredAlternatives(),
plan.getSampleRecordsDefinition().getRecords().size(),
true);
/*
* establish references of Experiment.uploads
*/
HashMap<String, SampleObject> records = new HashMap<String, SampleObject>();
for (SampleObject record : plan.getSampleRecordsDefinition().getRecords()) {
records.put(record.getShortName(), record);
}
for (Alternative alt : plan.getAlternativesDefinition().getAlternatives()) {
if ((alt.getExperiment() != null) && (alt.getExperiment() instanceof ExperimentWrapper )) {
alt.setExperiment(((ExperimentWrapper)alt.getExperiment()).getExperiment(records));
}
}
// DESCRIBE all DigitalObjects with Jhove.
for (SampleObject record : plan.getSampleRecordsDefinition().getRecords()) {
if (record.isDataExistent()) {
// characterise
try {
record.setJhoveXMLString(new JHoveAdaptor().describe(record));
} catch(Throwable e) {
log.error("Error running Jhove for record " + record.getShortName() + ". " + e.getMessage(), e);
}
for (Alternative alt : plan.getAlternativesDefinition().getAlternatives()) {
DigitalObject result = alt.getExperiment().getResults().get(record);
if (result != null && result.isDataExistent()) {
try {
result.setJhoveXMLString(new JHoveAdaptor().describe(result));
} catch(Throwable e) {
log.error("Error running Jhove for record " + record.getShortName()
+ ", alternative " + alt.getName() + ". " + e.getMessage(), e);
}
}
}
}
}
// CHECK NUMERIC TRANSFORMER THRESHOLDS
for (Leaf l: plan.getTree().getRoot().getAllLeaves()) {
eu.planets_project.pp.plato.model.transform.Transformer t = l.getTransformer();
if (t != null && t instanceof NumericTransformer) {
NumericTransformer nt = (NumericTransformer) t;
if (!nt.checkOrder()) {
StringBuffer sb = new StringBuffer("NUMERICTRANSFORMER THRESHOLD ERROR ");
sb.append(l.getName())
.append("::NUMERICTRANSFORMER:: ");
sb.append(nt.getThreshold1()).append(" ")
.append(nt.getThreshold2()).append(" ")
.append(nt.getThreshold3()).append(" ")
.append(nt.getThreshold4()).append(" ")
.append(nt.getThreshold5());
log.error(sb.toString());
}
}
}
/*
* establish references to selected alternative
*/
HashMap<String, Alternative> alternatives = new HashMap<String, Alternative>();
for (Alternative alt : plan.getAlternativesDefinition().getAlternatives()) {
alternatives.put(alt.getName(), alt);
}
if ((plan.getRecommendation() != null) && (plan.getRecommendation() instanceof RecommendationWrapper)) {
plan.setRecommendation(((RecommendationWrapper)plan.getRecommendation()).getRecommendation(alternatives));
}
if ((plan.getState().getValue() == PlanState.ANALYSED) &&
((plan.getRecommendation() == null)||(plan.getRecommendation().getAlternative()== null))) {
/*
* This project is NOT completely analysed
*/
plan.getState().setValue(PlanState.ANALYSED - 1);
}
} else {
throw new SAXException("Could not find any project data.");
}
}
} finally {
OS.deleteDirectory(tempDir);
/*
* Importing big plans results in an increasing memory consumption
* strange: The rise of memory consumption occurs when persisting the loaded project
* NOT during parsing with the digester
*/
System.gc();
}
return this.plans;
}
/**
*
* @param args
* first entry is the filename of the xml-file to be imported
* second entry is the name of the output-file
*/
public static void main(String[] args) {
ProjectImporter projectImp = new ProjectImporter();
ProjectExporter exporter = new ProjectExporter();
try {
for (Plan plan : projectImp.importProjects(args[0])) {
System.out.println("Imported : "
+ plan.getPlanProperties().getName());
// export the imported project
FileOutputStream out = new FileOutputStream(args[1]);
XMLWriter writer = new XMLWriter(out,
ProjectExporter.prettyFormat);
writer.write(exporter.exportToXml(plan));
writer.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
/**
* Create a rule for reading an upload entry for the given location
* <code>pattern</code>, and use the <code>method</code> to set the upload
* object.
*
* @param digester
* @param pattern
* @param method
*/
private static void addCreateUpload(Digester digester, String pattern,
String method, Class objectType) {
digester.addObjectCreate(pattern, objectType);
digester.addSetProperties(pattern);
if ((method != null) && (!"".equals(method)))
digester.addSetNext(pattern, method);
/*
* Note: It is not possible to read element data, process it and pass it
* to a function with a simple digester Rule, neither you can define a
* factory to read the data of an element.
*
* So we have to do it the other way round: (remember: the function
* added last is executed first!)
*/
// 1. Create a BinaryDataWrapper if a <data> element is encountered
digester.addObjectCreate(pattern + "/data", BinaryDataWrapper.class);
// 3. Finally call setData on the BinaryDataWrapper(!) on top with the
// object next to top as argument
// The BinaryDataWrapper will call setData on to object next to top with
// the previously read and decoded data
digester.addSetTop(pattern + "/data", "setData");
// 2. Call setFromBase64Encoded on the BinaryDataWrapper to read the
// elements content
digester.addCallMethod(pattern + "/data", "setFromBase64Encoded", 0);
}
public void setFileVersion(String fileVersion) {
this.fileVersion = fileVersion;
}
/**
* This method adds rules for name, properties, scales, modes and mappings
* only! Rules for importing measured values of alternatives are defined
* seperately in importProjects()! (Refactored to its own method by Kevin)
*/
private static void addTreeParsingRulesToDigester(Digester digester) {
digester.addObjectCreate("*/plan/tree", ObjectiveTree.class);
digester.addSetProperties("*/plan/tree");
digester.addSetNext("*/plan/tree", "setTree");
digester.addObjectCreate("*/node/node", Node.class);
digester.addSetProperties("*/node/node");
digester.addSetNext("*/node/node", "addChild");
digester.addCallMethod("*/node/description", "setDescription", 0);
digester.addObjectCreate("*/plan/tree/node", Node.class);
digester.addSetProperties("*/plan/tree/node");
digester.addSetNext("*/plan/tree/node", "setRoot");
digester.addObjectCreate("*/leaf", Leaf.class);
digester.addSetProperties("*/leaf");
digester.addSetNext("*/leaf", "addChild");
digester.addFactoryCreate("*/leaf/aggregationMode",
SampleAggregationModeFactory.class);
digester.addSetNext("*/leaf/aggregationMode", "setAggregationMode");
digester.addCallMethod("*/leaf/description", "setDescription", 0);
digester.addObjectCreate("*/measurementInfo", MeasurementInfo.class);
digester.addSetNext("*/measurementInfo", "setMeasurementInfo");
addPropertyRules(digester, "*/measurementInfo/property");
// and the selected metric
addMetricRules(digester, "*/measurementInfo/metric", "setMetric");
/*
* for each scale-type a set of rules
*/
addCreateScale(digester, BooleanScale.class);
addCreateScale(digester, FloatRangeScale.class);
addCreateScale(digester, FloatScale.class);
addCreateScale(digester, IntegerScale.class);
addCreateScale(digester, IntRangeScale.class);
addCreateScale(digester, OrdinalScale.class);
addCreateScale(digester, PositiveFloatScale.class);
addCreateScale(digester, PositiveIntegerScale.class);
addCreateScale(digester, YanScale.class);
addCreateScale(digester, FreeStringScale.class);
/*
* for each transformer type a set of rules
*/
digester.addObjectCreate("*/leaf/numericTransformer",
NumericTransformer.class);
digester.addSetProperties("*/leaf/numericTransformer");
digester.addFactoryCreate("*/leaf/numericTransformer/mode",
TransformationModeFactory.class);
digester.addSetNext("*/leaf/numericTransformer/mode", "setMode");
digester
.addBeanPropertySetter(
"*/leaf/numericTransformer/thresholds/threshold1",
"threshold1");
digester
.addBeanPropertySetter(
"*/leaf/numericTransformer/thresholds/threshold2",
"threshold2");
digester
.addBeanPropertySetter(
"*/leaf/numericTransformer/thresholds/threshold3",
"threshold3");
digester
.addBeanPropertySetter(
"*/leaf/numericTransformer/thresholds/threshold4",
"threshold4");
digester
.addBeanPropertySetter(
"*/leaf/numericTransformer/thresholds/threshold5",
"threshold5");
digester.addSetNext("*/leaf/numericTransformer", "setTransformer");
// digester.addObjectCreate("*/numericTransformer/thresholds",
// LinkedHashMap.class);
// digester.addSetNext("*/numericTransformer/thresholds",
// "setThresholds");
// digester.addFactoryCreate("*/thresholds/threshold",
// NumericTransformerThresholdFactory.class);
digester.addObjectCreate("*/leaf/ordinalTransformer",
OrdinalTransformer.class);
digester.addSetProperties("*/leaf/ordinalTransformer");
digester.addSetNext("*/leaf/ordinalTransformer", "setTransformer");
digester.addObjectCreate("*/ordinalTransformer/mappings",
LinkedHashMap.class);
digester.addSetNext("*/ordinalTransformer/mappings", "setMapping");
digester.addFactoryCreate("*/mappings/mapping",
OrdinalTransformerMappingFactory.class);
digester.addRule("*/mappings/mapping", new CallMethodRule(1, "put", 2)); // method
// with
// two
// params
digester.addCallParam("*/mappings/mapping", 0, "ordinal"); // use
// attribute
// "ordinal"
// as first
// argument
digester.addCallParam("*/mappings/mapping", 1, true); // and the object
// on the stack as
// second
}
private static void addCreateResultValue(Digester digester, Class c) {
String name = c.getName();
name = name.substring(name.lastIndexOf(".") + 1);
name = name.substring(0, 1).toLowerCase() + name.substring(1);
String pattern = "*/" + name.replace("Value", "Result");
digester.addObjectCreate(pattern, c);
digester.addSetProperties(pattern);
digester.addBeanPropertySetter(pattern + "/value");
digester.addBeanPropertySetter(pattern + "/comment");
digester.addSetNext(pattern, "add");
}
private static void addCreateValue(Digester digester, Class c,
String setNextMethod) {
String name = c.getName();
name = name.substring(name.lastIndexOf(".") + 1);
name = name.substring(0, 1).toLowerCase() + name.substring(1);
String pattern = "*/" + name;
digester.addObjectCreate(pattern, c);
// digester.addSetProperties(pattern);
digester.addBeanPropertySetter(pattern + "/value");
digester.addSetNext(pattern, setNextMethod);
}
private static void addCreateScale(Digester digester, Class c) {
String name = c.getName();
name = name.substring(name.lastIndexOf(".") + 1);
name = name.substring(0, 1).toLowerCase() + name.substring(1);
String pattern = "*/" + name;
digester.addObjectCreate(pattern, c);
digester.addSetProperties(pattern);
digester.addSetNext(pattern, "setScale");
}
private static void addPropertyRules(Digester digester, String pattern) {
digester.addObjectCreate(pattern, MeasurableProperty.class);
digester.addSetNext(pattern, "setProperty");
digester.addSetProperties(pattern);
// there is no property categoryAsString, but a setter ...
digester.addBeanPropertySetter( pattern + "/category", "categoryAsString");
digester.addBeanPropertySetter(pattern + "/propertyId");
digester.addBeanPropertySetter(pattern + "/name");
digester.addBeanPropertySetter(pattern + "/description");
// scale is created automatically with global rule
// digester.addObjectCreate(pattern + "/possibleMetrics", ArrayList.class);
// digester.addSetNext(pattern + "/possibleMetrics", "setPossibleMetrics");
// addMetricRules(digester, "*/possibleMetrics/metric", "add");
}
private static void addMetricRules(Digester digester, String pattern,
String method) {
digester.addObjectCreate(pattern, Metric.class);
digester.addSetProperties(pattern);
digester.addBeanPropertySetter(pattern + "/metricId");
digester.addBeanPropertySetter(pattern + "/name");
digester.addBeanPropertySetter(pattern + "/description");
// scale is created automatically with "global" rule
digester.addSetNext(pattern, method);
}
public List<String> getAppliedTransformations() {
return appliedTransformations;
}
}