package eu.scape_project.planning.sla; import java.io.IOException; import java.io.StringWriter; import java.util.List; import org.dom4j.Document; 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 eu.scape_project.planning.model.Plan; import eu.scape_project.planning.model.measurement.EvaluationScope; 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.validation.ValidationError; public class QLDGenerator { private final static String CONTEXT_MEASURE = "measure[@type='${MEASURE}' and (@subject != 'SourceObject')]"; private final static Namespace SCHEMATRON_NS = new Namespace("", "http://purl.oclc.org/dsdl/schematron"); private Document doc; private Element root; public QLDGenerator() { } public Document getQldNode() { return doc; } public String getQLDs(){ OutputFormat prettyFormat = new OutputFormat(" ", true, "UTF-8"); StringWriter qldWriter = new StringWriter(); XMLWriter writer = new XMLWriter(qldWriter , prettyFormat); try { writer.write(doc); } catch (Exception e) { } finally { try { writer.close(); } catch (IOException e) { } } return qldWriter.toString(); } /** * Generates triggers and QLDs based on decision criteria of the plan. * * @param plan */ public void generateQLD(Plan plan) { doc = DocumentHelper.createDocument(); root = doc.addElement("schema"); root.clearContent(); root.add(SCHEMATRON_NS); Element pattern = root.addElement(new QName("pattern", SCHEMATRON_NS)); String ident = (null == plan.getPlanProperties().getRepositoryIdentifier()?"" : "("+plan.getPlanProperties().getRepositoryIdentifier()+")"); pattern.addElement("title") .setText("QLDs based on plan " + plan.getPlanProperties().getName() + ident); List<Leaf> leaves = plan.getTree().getRoot().getAllLeaves(); List<ValidationError> errors = null; for (Leaf leaf : leaves) { if (leaf.isCompletelySpecified(errors) && leaf.isCompletelyTransformed(errors) && leaf.isMapped()) { if (EvaluationScope.OBJECT == leaf.getMeasure().getAttribute().getCategory().getScope()) { // generate QLD for Preservation Action Plan addQLD(pattern, leaf); } } } } /** * Adds a QLD derived from the decision criteria of the given leaf to the given parent node. * * <schema xmlns="http://purl.oclc.org/dsdl/schematron"> * <pattern> * <title>measures rules</title> * <rule context="measure[@type='similarity']"> * <assert test=". > 0.87">Similarity score must be greater than 0.87</assert> * </rule> * </pattern> * </schema> * * @param parent * @param leaf */ private void addQLD(Element parent, Leaf leaf) { // is this a drop out criteria? if (leaf.getTransformer() instanceof OrdinalTransformer) { //Element search for the unacceptable values (there can be more than one!) String explanation = leaf.getMeasure().getName() + " must have (one) of the the following values: ["; String test = ""; OrdinalTransformer ordinalT = (OrdinalTransformer)leaf.getTransformer(); for (String key : ordinalT.getMapping().keySet()) { double value = ordinalT.getMapping().get(key).getValue(); if (Double.compare(value, 0.0) <= 0) { test = test + "(. != '" + key + "') and "; } else { explanation = explanation + key + ", "; } } if (test.length() > 0) { test = test.substring(0, test.length() - 5); explanation = explanation.substring(0, explanation.length() - 2) + "]"; Element rule = parent.addElement("rule"); rule.addAttribute("context", CONTEXT_MEASURE.replace("${MEASURE}", leaf.getMeasure().getUri())); Element assertEl = rule.addElement("assert"); assertEl.addAttribute("test", test); assertEl.setText(explanation); } } else if (leaf.getTransformer() instanceof NumericTransformer){ NumericTransformer numericT = (NumericTransformer)leaf.getTransformer(); String explanation = leaf.getMeasure().getName() + " must be "; String operator; if (numericT.hasIncreasingOrder()) { explanation = explanation + " greater than or equal to " + numericT.getThreshold1(); operator = " >= "; } else { explanation = explanation + " less than or equal to " + numericT.getThreshold1(); operator = " <= "; } String test = " . " + operator + " " + numericT.getThreshold1(); Element rule = parent.addElement("rule"); rule.addAttribute("context", CONTEXT_MEASURE.replace("${MEASURE}", leaf.getMeasure().getUri())); Element assertEl = rule.addElement("assert"); assertEl.addAttribute("test", test); assertEl.setText(explanation); } } }