/**
* SPINdle (version 2.2.2)
* Copyright (C) 2009-2012 NICTA Ltd.
*
* This file is part of SPINdle project.
*
* SPINdle is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SPINdle is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SPINdle. If not, see <http://www.gnu.org/licenses/>.
*
* @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory
*/
package spindle.io.outputter;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.xml.bind.Marshaller;
import spindle.core.dom.DomConst;
import spindle.io.OutputterException;
import spindle.io.xjc.XjcUtilities;
import spindle.io.xjc.dom2.Conclusions;
import spindle.io.xjc.dom2.CtConclusion;
import spindle.io.xjc.dom2.CtInterval;
import spindle.io.xjc.dom2.CtLiteral;
import spindle.io.xjc.dom2.CtLiteralBooleanFunctionPair;
import spindle.io.xjc.dom2.CtLiteralVariable;
import spindle.io.xjc.dom2.CtLiteralVariablePair;
import spindle.io.xjc.dom2.CtModeConflictRule;
import spindle.io.xjc.dom2.CtModeConversionRule;
import spindle.io.xjc.dom2.CtModeExclusionRule;
import spindle.io.xjc.dom2.CtPredicates;
import spindle.io.xjc.dom2.CtRule;
import spindle.io.xjc.dom2.CtRuleBodyLiterals;
import spindle.io.xjc.dom2.CtRuleHeadLiterals;
import spindle.io.xjc.dom2.CtSuperiority;
import spindle.io.xjc.dom2.ObjectFactory;
import spindle.io.xjc.dom2.Rules;
import spindle.io.xjc.dom2.Theory;
/**
* Defeasible theory and conclusions outputter in XML.
* It is implemented based on the classes generated by <a href="https://jaxb.java.net/">JAXB</a> with the specified XML
* schema.
* It is going to be used to replace the old XML theory and conclusions outputter class (
* {@link spindle.io.outputter.XmlTheoryOutputter}).
*
* @author H.-P. Lam (oleklam@gmail.com), National ICT Australia - Queensland Research Laboratory
* @version Last modified 2012.05.28
* @since version 2.2.2
* @see spindle.io.xjc.dom2
* @see spindle.io.outputter.XmlTheoryOutputter
*/
public class XmlTheoryOutputter2 extends AbstractTheoryOutputter {
public static final String OUTPUTTER_TYPE = "xml";
private static final String LITERAL_PREDICATE_DEFAULT_VALUE = DomConst.Literal.DEFAULT_PREDICATE_VALUE;
private static ObjectFactory objectFactory = null;
private static XmlTheoryOutputter2 INSTANCE = null;
private static Marshaller ruleMarshaller = null;
private Marshaller theoryMarshaller = null;
private Marshaller conclusionsMarshaller = null;
public static String getTheoryAsXmlString(spindle.core.dom.Theory theory) throws OutputterException {
ByteArrayOutputStream writer = new ByteArrayOutputStream();
XmlTheoryOutputter2 outputter = new XmlTheoryOutputter2();
outputter.save(writer, theory);
return writer.toString();
}
public static String getConclusionsAsXmlString(List<spindle.core.dom.Conclusion> conclusionsAsList) throws OutputterException {
ByteArrayOutputStream writer = new ByteArrayOutputStream();
XmlTheoryOutputter2 outputter = new XmlTheoryOutputter2();
outputter.save(writer, conclusionsAsList);
return writer.toString();
}
public static String getRuleAsXmlString(spindle.core.dom.Rule rule) throws OutputterException {
try {
if (null == INSTANCE) INSTANCE = new XmlTheoryOutputter2();
if (null == ruleMarshaller) ruleMarshaller = XjcUtilities.getRuleMarshaller();
CtRule cRule = INSTANCE.generateRule(rule);
Rules cRules = objectFactory.createRules();
cRules.setRule(cRule);
ByteArrayOutputStream writer = new ByteArrayOutputStream();
ruleMarshaller.marshal(cRules, writer);
String ruleStrDummy = writer.toString();
int sloc = ruleStrDummy.indexOf("<rule ");
int eloc = ruleStrDummy.indexOf("</rules>");
String ruleStr = ruleStrDummy.substring(sloc, eloc);
return ruleStr.replaceAll("\n ", "\n").trim();
} catch (Exception e) {
throw new OutputterException(e);
}
}
public XmlTheoryOutputter2() {
super(OUTPUTTER_TYPE);
if (null == objectFactory) objectFactory = XjcUtilities.getObjectFactory();
}
@Override
protected void saveToStream(OutputStream os, spindle.core.dom.Theory theory) throws OutputterException {
try {
if (null == theoryMarshaller) theoryMarshaller = XjcUtilities.getTheoryMarshaller();
Theory cTheory = objectFactory.createTheory();
if (!"".equals(theory.getDescription())) cTheory.setDescription(theory.getDescription());
List<Object> factsOrRules = generateFactOrRule(theory.getFactsAndAllRules());
if (null != factsOrRules) cTheory.getFactOrRule().addAll(factsOrRules);
List<CtSuperiority> superiorities = generateSuperiority(theory.getAllSuperiority());
if (null != superiorities) cTheory.getSuperiority().addAll(superiorities);
List<CtModeConversionRule> modeConversionRules = generateModeConversionRules(theory.getAllModeConversionRules());
if (null != modeConversionRules) cTheory.getConvert().addAll(modeConversionRules);
List<CtModeConflictRule> modeConflictRules = generateModeConflictRules(theory.getAllModeConflictRules());
if (null != modeConflictRules) cTheory.getConflict().addAll(modeConflictRules);
List<CtModeExclusionRule> modeExclusionRules = generateModeExclusionRules(theory.getAllModeExclusionRules());
if (null != modeExclusionRules) cTheory.getExclude().addAll(modeExclusionRules);
List<CtLiteralVariablePair> literalVariables = generateLiteralVariables(theory.getLiteralVariables());
if (null != literalVariables) cTheory.getLiteralVariable().addAll(literalVariables);
List<CtLiteralBooleanFunctionPair> literalBooleanFunctions = generateLiteralBooleanFunctions(theory
.getLiteralBooleanFunctions());
if (null != literalBooleanFunctions) cTheory.getLiteralBooleanFunction().addAll(literalBooleanFunctions);
theoryMarshaller.marshal(cTheory, os);
} catch (Exception e) {
throw new OutputterException(e);
}
}
@Override
protected void saveToStream(OutputStream os, List<spindle.core.dom.Conclusion> conclusionsAsList) throws OutputterException {
try {
if (null == conclusionsMarshaller) conclusionsMarshaller = XjcUtilities.getConclusionsMarshaller();
Conclusions cConclusions = objectFactory.createConclusions();
List<CtConclusion> conclusionsList = cConclusions.getConclusion();
for (spindle.core.dom.Conclusion conclusion : conclusionsAsList) {
CtConclusion cConclusion = objectFactory.createCtConclusion();
cConclusion.setTag(conclusion.getConclusionType().getTextTag());
cConclusion.setLiteral(generateLiteral(conclusion.getLiteral()));
conclusionsList.add(cConclusion);
}
conclusionsMarshaller.marshal(cConclusions, os);
} catch (Exception e) {
throw new OutputterException(e);
}
}
private List<CtLiteralVariablePair> generateLiteralVariables(
Map<spindle.core.dom.LiteralVariable, spindle.core.dom.LiteralVariable> literalVariables) {
if (null == literalVariables || literalVariables.size() == 0) return null;
List<CtLiteralVariablePair> cLiteralVariablePairs = new ArrayList<CtLiteralVariablePair>();
for (Entry<spindle.core.dom.LiteralVariable, spindle.core.dom.LiteralVariable> entry : literalVariables.entrySet()) {
CtLiteralVariable name = generateLiteralVariable(entry.getKey());
CtLiteralVariable value = generateLiteralVariable(entry.getValue());
CtLiteralVariablePair cLiteralVariablePair = objectFactory.createCtLiteralVariablePair();
cLiteralVariablePair.setName(name);
cLiteralVariablePair.setValue(value);
cLiteralVariablePairs.add(cLiteralVariablePair);
}
return cLiteralVariablePairs.size() == 0 ? null : cLiteralVariablePairs;
}
private List<CtLiteralBooleanFunctionPair> generateLiteralBooleanFunctions(
Map<spindle.core.dom.LiteralVariable, spindle.core.dom.LiteralVariable> literalBooleanFunctions) {
if (null == literalBooleanFunctions || literalBooleanFunctions.size() == 0) return null;
List<CtLiteralBooleanFunctionPair> cLiteralFunctionPairs = new ArrayList<CtLiteralBooleanFunctionPair>();
for (Entry<spindle.core.dom.LiteralVariable, spindle.core.dom.LiteralVariable> entry : literalBooleanFunctions.entrySet()) {
CtLiteralVariable name = generateLiteralVariable(entry.getKey());
String value = entry.getValue().getName();
CtLiteralBooleanFunctionPair cLiteralFunctionPair = objectFactory.createCtLiteralBooleanFunctionPair();
cLiteralFunctionPair.setName(name);
cLiteralFunctionPair.setValue(value);
cLiteralFunctionPairs.add(cLiteralFunctionPair);
}
return cLiteralFunctionPairs.size() == 0 ? null : cLiteralFunctionPairs;
}
private CtLiteralVariable generateLiteralVariable(spindle.core.dom.LiteralVariable literalVariable) {
CtLiteralVariable clv = objectFactory.createCtLiteralVariable();
clv.setAtom(literalVariable.getName());
CtPredicates cPredicates = generatePredicates(literalVariable.getPredicates());
if (null != cPredicates) clv.setPredicates(cPredicates);
return clv;
}
private List<CtModeConversionRule> generateModeConversionRules(Map<String, Set<String>> conversionRules) {
if (null == conversionRules || conversionRules.size() == 0) return null;
List<CtModeConversionRule> modeRules = new ArrayList<CtModeConversionRule>();
for (Entry<String, Set<String>> entry : conversionRules.entrySet()) {
CtModeConversionRule cConversionRule = objectFactory.createCtModeConversionRule();
cConversionRule.setFrom(entry.getKey());
cConversionRule.getTo().addAll(entry.getValue());
modeRules.add(cConversionRule);
}
return modeRules.size() == 0 ? null : modeRules;
}
private List<CtModeConflictRule> generateModeConflictRules(Map<String, Set<String>> conflictRules) {
if (null == conflictRules || conflictRules.size() == 0) return null;
List<CtModeConflictRule> modeRules = new ArrayList<CtModeConflictRule>();
for (Entry<String, Set<String>> entry : conflictRules.entrySet()) {
CtModeConflictRule cConflictRule = objectFactory.createCtModeConflictRule();
cConflictRule.setMode(entry.getKey());
cConflictRule.getConflictWIth().addAll(entry.getValue());
modeRules.add(cConflictRule);
}
return modeRules.size() == 0 ? null : modeRules;
}
private List<CtModeExclusionRule> generateModeExclusionRules(Map<String, Set<String>> exclusionRules) {
if (null == exclusionRules || exclusionRules.size() == 0) return null;
List<CtModeExclusionRule> modeRules = new ArrayList<CtModeExclusionRule>();
for (Entry<String, Set<String>> entry : exclusionRules.entrySet()) {
CtModeExclusionRule cExcludeRules = objectFactory.createCtModeExclusionRule();
cExcludeRules.setMode(entry.getKey());
cExcludeRules.getExcludeWith().addAll(entry.getValue());
modeRules.add(cExcludeRules);
}
return modeRules.size() == 0 ? null : modeRules;
}
private List<CtSuperiority> generateSuperiority(List<spindle.core.dom.Superiority> superiorities) {
if (superiorities.size() == 0) return null;
List<CtSuperiority> cSuperiorities = new ArrayList<CtSuperiority>();
for (spindle.core.dom.Superiority superiority : superiorities) {
CtSuperiority cSuperiority = objectFactory.createCtSuperiority();
cSuperiority.setSuperior(superiority.getSuperior());
cSuperiority.setInferior(superiority.getInferior());
cSuperiorities.add(cSuperiority);
}
return cSuperiorities.size() == 0 ? null : cSuperiorities;
}
private List<Object> generateFactOrRule(Map<String, spindle.core.dom.Rule> factsOrRules) {
List<Object> factOrRule = new ArrayList<Object>();
Object obj = null;
for (spindle.core.dom.Rule rule : factsOrRules.values()) {
switch (rule.getRuleType()) {
case FACT:
spindle.core.dom.Literal headLiteral = rule.getHeadLiterals().get(0);
obj = generateLiteral(headLiteral);
break;
case STRICT:
case DEFEASIBLE:
case DEFEATER:
obj = generateRule(rule);
break;
default:
}
if (null != obj) factOrRule.add(obj);
}
return factOrRule.size() == 0 ? null : factOrRule;
}
private CtRule generateRule(spindle.core.dom.Rule rule) {
CtRule cRule = objectFactory.createCtRule();
switch (rule.getRuleType()) {
case STRICT:
cRule.setRuletype("STRICT");
break;
case DEFEASIBLE:
cRule.setRuletype("DEFEASIBLE");
break;
case DEFEATER:
cRule.setRuletype("DEFEATER");
break;
default:
}
String ruleLabel = rule.getLabel();
if (!(null == ruleLabel || "".equals(ruleLabel))) {
if (!ruleLabel.startsWith(spindle.core.dom.Theory.DEFAULT_RULE_LABEL_PREFIX)) cRule.setLabel(ruleLabel);
}
spindle.core.dom.Mode mode = rule.getMode();
if (null != mode && !"".equals(mode.getName())) cRule.setMode(mode.getName());
List<CtLiteral> cHeadLiterals = generateLiterals(rule.getHeadLiterals());
if (null != cHeadLiterals) {
CtRuleHeadLiterals cHead = objectFactory.createCtRuleHeadLiterals();
cHead.getLiteral().addAll(cHeadLiterals);
cRule.setHead(cHead);
}
List<CtLiteral> cBodyLiterals = generateLiterals(rule.getBodyLiterals());
if (null != cBodyLiterals) {
CtRuleBodyLiterals cBody = objectFactory.createCtRuleBodyLiterals();
if (cBodyLiterals.size() == 1) {
cBody.setLiteral(cBodyLiterals.get(0));
} else {
CtRuleBodyLiterals.And bodyAnd = objectFactory.createCtRuleBodyLiteralsAnd();
bodyAnd.getLiteral().addAll(cBodyLiterals);
cBody.setAnd(bodyAnd);
}
cRule.setBody(cBody);
}
return cRule;
}
private List<CtLiteral> generateLiterals(List<spindle.core.dom.Literal> literals) {
if (null == literals || literals.size() == 0) return null;
List<CtLiteral> cLiterals = new ArrayList<CtLiteral>();
for (spindle.core.dom.Literal literal : literals) {
cLiterals.add(generateLiteral(literal));
}
return cLiterals;
}
private CtLiteral generateLiteral(spindle.core.dom.Literal literal) {
CtLiteral cLiteral = objectFactory.createCtLiteral();
if (literal.isNegation()) {
CtLiteral.Not cNegLiteral = objectFactory.createCtLiteralNot();
cNegLiteral.setAtom(literal.getName());
cLiteral.getNot().add(cNegLiteral);
} else {
cLiteral.setAtom(literal.getName());
}
spindle.core.dom.Mode mode = literal.getMode();
if (null != mode && !"".equals(mode.getName())) {
if (mode.isNegation()) {
CtLiteral.Not cNegMode = objectFactory.createCtLiteralNot();
cNegMode.setMode(mode.getName());
cLiteral.getNot().add(cNegMode);
} else {
cLiteral.setMode(mode.getName());
}
}
spindle.core.dom.Temporal temporal = literal.getTemporal();
if (null != temporal && temporal.hasTemporalInfo()) {
CtInterval cInterval = objectFactory.createCtInterval();
if (Long.MIN_VALUE != temporal.getStartTime()) cInterval.setStart(temporal.getStartTime());
if (Long.MAX_VALUE != temporal.getEndTime()) cInterval.setEnd(temporal.getEndTime());
cLiteral.setInterval(cInterval);
}
CtPredicates cPredicates = generatePredicates(literal.getPredicates());
if (null != cPredicates) cLiteral.setPredicates(cPredicates);
return cLiteral;
}
private CtPredicates generatePredicates(String[] predicates) {
if (null != predicates && predicates.length > 0) {
List<String> pList = new ArrayList<String>();
if (predicates.length == 1) {
String p = predicates[0];
if (!LITERAL_PREDICATE_DEFAULT_VALUE.equals(p)) pList.add(p);
} else {
for (String p : predicates) {
pList.add(LITERAL_PREDICATE_DEFAULT_VALUE.equals(p) ? "" : p);
}
}
if (pList.size() > 0) {
CtPredicates cPredicates = objectFactory.createCtPredicates();
cPredicates.getPredicate().addAll(pList);
return cPredicates;
}
}
return null;
}
}