/**
* 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.parser;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import spindle.core.dom.DomUtilities;
import spindle.core.dom.RuleException;
import spindle.core.dom.TheoryException;
import spindle.io.ParserException;
import spindle.io.outputter.XmlTheoryOutputter2;
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.Rules;
import spindle.io.xjc.dom2.Theory;
import spindle.sys.AppLogger;
/**
* Defeasible theory and conclusions parser for theory represented using XML.<br/>
* 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 replace the old XML theory and conclusions parser class ({@link spindle.io.parser.XmlTheoryParser}).
*
* @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.parser.XmlTheoryParser
*/
public class XmlTheoryParser2 extends AbstractTheoryParser {
public static final String PARSER_TYPE = XmlTheoryOutputter2.OUTPUTTER_TYPE;
private static XmlTheoryParser2 INSTANCE = null;
private static Unmarshaller ruleUnmarshaller = null;
private static final String RULE_PREFIX = "<rules xmlns=\"http://spin.nicta.org.au/spindle/spindleDefeasibleTheory2.xsd\" "
+ "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
+">";
private static final String RULE_POSTFIX = "</rules>";
public static spindle.core.dom.Theory getTheory(String xmlString, AppLogger logger) throws ParserException {
if (null == INSTANCE) INSTANCE = new XmlTheoryParser2();
try {
InputStream ins = new ByteArrayInputStream(xmlString.replaceAll("[\t\r\n]", "").getBytes());
if (null != logger) INSTANCE.setAppLogger(logger);
return INSTANCE.getTheory(ins);
} catch (Exception e) {
throw new ParserException(e);
} finally {
INSTANCE.resetAppLogger();
}
}
public static Map<spindle.core.dom.Literal, Map<spindle.core.dom.ConclusionType, spindle.core.dom.Conclusion>> getConclusions(
String xmlString, AppLogger logger) throws ParserException {
if (null == INSTANCE) INSTANCE = new XmlTheoryParser2();
try {
InputStream ins = new ByteArrayInputStream(xmlString.replaceAll("[\t\r\n]", "").getBytes());
if (null != logger) INSTANCE.setAppLogger(logger);
return INSTANCE.getConclusions(ins);
} catch (Exception e) {
throw new ParserException(e);
} finally {
INSTANCE.resetAppLogger();
}
}
public static spindle.core.dom.Rule getRule(String xmlString, AppLogger logger) throws ParserException {
try {
if (null == INSTANCE) INSTANCE = new XmlTheoryParser2();
if (null != logger) INSTANCE.setAppLogger(logger);
String ruleStr = RULE_PREFIX + xmlString + RULE_POSTFIX;
InputStream ins = new ByteArrayInputStream(ruleStr.replaceAll("[\t\r\n]", "").getBytes());
if (null == ruleUnmarshaller) ruleUnmarshaller = XjcUtilities.getRuleUnmarshaller();
Rules cRule = (Rules) ruleUnmarshaller.unmarshal(ins);
spindle.core.dom.Rule rule = INSTANCE.generateRule(cRule.getRule());
if (rule.getLabel().startsWith(TEMP_RULE_LABEL)) rule.setLabel(spindle.core.dom.Theory.DEFAULT_RULE_LABEL_PREFIX + "0001");
return rule;
} catch (Exception e) {
throw new ParserException(e);
} finally {
INSTANCE.resetAppLogger();
}
}
private Unmarshaller theoryUnmarshaller = null;
private Unmarshaller conclusionsUnmarshaller = null;
private int ruleCounter = 0;
public XmlTheoryParser2() {
super(PARSER_TYPE);
}
@Override
protected void generateTheory(InputStream ins) throws ParserException {
try {
if (null == theoryUnmarshaller) theoryUnmarshaller = XjcUtilities.getTheoryUnmarshaller();
Theory cTheory = (Theory) theoryUnmarshaller.unmarshal(ins);
theory = new spindle.core.dom.Theory();
ruleCounter = 0;
theory.setDescription(cTheory.getDescription());
List<Object> factOrRule = cTheory.getFactOrRule();
for (Object obj : factOrRule) {
if (obj instanceof CtRule) {
spindle.core.dom.Rule newRule = generateRule((CtRule) obj);
if (newRule.getLabel().startsWith(TEMP_RULE_LABEL)) addPendingRule(newRule);
else theory.addRule(newRule);
} else if (obj instanceof CtLiteral) {
spindle.core.dom.Rule newRule = generateFact((CtLiteral) obj);
if (newRule.getLabel().startsWith(TEMP_RULE_LABEL)) addPendingRule(newRule);
else theory.addFact(newRule);
} else {
throw new ParserException("unknown class in fact or rule: " + obj.getClass().getName());
}
}
generateSuperiority(cTheory.getSuperiority());
generateModeConversionRules(cTheory.getConvert());
generateModeConflictRules(cTheory.getConflict());
generateModeExclusionRules(cTheory.getExclude());
generateLiteralVariablePair(cTheory.getLiteralVariable());
generateLiteralBooleanFunctionPair(cTheory.getLiteralBooleanFunction());
} catch (Exception e) {
theory = null;
throw new ParserException(e);
}
}
@Override
protected Map<spindle.core.dom.Literal, Map<spindle.core.dom.ConclusionType, spindle.core.dom.Conclusion>> generateConclusions(
InputStream ins) throws ParserException {
Map<spindle.core.dom.Literal, Map<spindle.core.dom.ConclusionType, spindle.core.dom.Conclusion>> conclusions = new TreeMap<spindle.core.dom.Literal, Map<spindle.core.dom.ConclusionType, spindle.core.dom.Conclusion>>();
try {
if (null == conclusionsUnmarshaller) conclusionsUnmarshaller = XjcUtilities.getConclusionsUnmarshaller();
Conclusions cConclusions = (Conclusions) conclusionsUnmarshaller.unmarshal(ins);
List<CtConclusion> conclusionList = cConclusions.getConclusion();
for (CtConclusion cConclusion : conclusionList) {
String conclusionTag = cConclusion.getTag();
CtLiteral cLiteral = cConclusion.getLiteral();
spindle.core.dom.ConclusionType conclusionType = getConclusionType_xml(conclusionTag);
spindle.core.dom.Literal literal = generateLiteral(cLiteral);
Map<spindle.core.dom.ConclusionType, spindle.core.dom.Conclusion> conclusionSet = conclusions.get(literal);
if (null == conclusionSet) {
conclusionSet = new TreeMap<spindle.core.dom.ConclusionType, spindle.core.dom.Conclusion>();
conclusions.put(literal, conclusionSet);
}
conclusionSet.put(conclusionType, new spindle.core.dom.Conclusion(conclusionType, literal));
}
if (conclusions.size() == 0) conclusions = null;
return conclusions;
} catch (JAXBException e) {
throw new ParserException(e);
}
}
private void generateSuperiority(List<CtSuperiority> superiorities) {
if (null == superiorities || superiorities.size() == 0) return;
for (CtSuperiority superiority : superiorities) {
String superior = superiority.getSuperior();
String inferior = superiority.getInferior();
theory.add(new spindle.core.dom.Superiority(superior, inferior));
}
}
private void generateModeConversionRules(List<CtModeConversionRule> modeConversionRules) {
if (null == modeConversionRules || modeConversionRules.size() == 0) return;
for (CtModeConversionRule conversionRule : modeConversionRules) {
List<String> conversionList = conversionRule.getTo();
if (null == conversionList || conversionList.size() == 0) continue;
String[] to = conversionList.toArray(new String[conversionList.size()]);
conversionList.toArray(to);
String from = conversionRule.getFrom();
theory.addModeConversionRules(from, to);
}
}
private void generateModeConflictRules(List<CtModeConflictRule> modeConflictRules) {
if (null == modeConflictRules || modeConflictRules.size() == 0) return;
for (CtModeConflictRule conflictRule : modeConflictRules) {
List<String> conflictList = conflictRule.getConflictWIth();
if (null == conflictList || conflictList.size() == 0) continue;
String[] conflictModes = conflictList.toArray(new String[conflictList.size()]);
String mode = conflictRule.getMode();
theory.addModeConflictRules(mode, conflictModes);
}
}
private void generateModeExclusionRules(List<CtModeExclusionRule> modeExclusionRules) {
if (null == modeExclusionRules || modeExclusionRules.size() == 0) return;
for (CtModeExclusionRule exclusionRule : modeExclusionRules) {
List<String> excludedList = exclusionRule.getExcludeWith();
if (null == excludedList || excludedList.size() == 0) continue;
String[] excludedModes = excludedList.toArray(new String[excludedList.size()]);
String mode = exclusionRule.getMode();
theory.addModeExclusionRules(mode, excludedModes);
}
}
private spindle.core.dom.Rule generateFact(CtLiteral cLiteral) throws ParserException, RuleException {
spindle.core.dom.Rule newRule = DomUtilities.getRule(theory.getUniqueRuleLabel(), spindle.core.dom.RuleType.FACT);
newRule.addHeadLiteral(generateLiteral(cLiteral));
return newRule;
}
private spindle.core.dom.Rule generateRule(CtRule cRule) throws ParserException, RuleException {
String ruleLabel = cRule.getLabel();
if (null == ruleLabel || "".equals(ruleLabel))
ruleLabel = TEMP_RULE_LABEL + spindle.core.dom.Theory.formatter.format(ruleCounter++);
// if ("".equals(ruleLabel)) ruleLabel = TEMP_RULE_LABEL + Theory.formatter.format(ruleCounter++);
// if (null == ruleLabel) ruleLabel = theory.getUniqueRuleLabel();
spindle.core.dom.RuleType ruleType = getRuleType_xml(cRule.getRuletype());
spindle.core.dom.Rule newRule = DomUtilities.getRule(ruleLabel, ruleType);
String ruleMode = cRule.getMode();
if (null != ruleMode && !"".equals(ruleMode.trim())) newRule.setMode(new spindle.core.dom.Mode(ruleMode, false));
CtInterval temporal = cRule.getInterval();
if (null != temporal) newRule.setTemporal(generateTemporal(temporal));
CtRuleHeadLiterals headLiterals = cRule.getHead();
for (CtLiteral cLiteral : headLiterals.getLiteral()) {
spindle.core.dom.Literal literal = generateLiteral(cLiteral);
newRule.addHeadLiteral(literal);
}
CtRuleBodyLiterals bodyLiterals = cRule.getBody();
if (null != bodyLiterals) {
CtLiteral bodyLiteral = bodyLiterals.getLiteral();
if (null != bodyLiteral) {
newRule.addBodyLiteral(generateLiteral(bodyLiteral));
} else {
CtRuleBodyLiterals.And literals = bodyLiterals.getAnd();
for (CtLiteral cLiteral : literals.getLiteral()) {
spindle.core.dom.Literal literal = generateLiteral(cLiteral);
newRule.addBodyLiteral(literal);
}
}
}
return newRule;
}
private void generateLiteralVariablePair(List<CtLiteralVariablePair> literalVariablesPairs) throws ParserException, TheoryException {
if (null == literalVariablesPairs || literalVariablesPairs.size() == 0) return;
for (CtLiteralVariablePair literalVariablePair : literalVariablesPairs) {
spindle.core.dom.LiteralVariable name = generateLiteralVariable(literalVariablePair.getName());
spindle.core.dom.LiteralVariable value = generateLiteralVariable(literalVariablePair.getValue());
theory.addLiteralVariable(name, value);
}
}
private void generateLiteralBooleanFunctionPair(List<CtLiteralBooleanFunctionPair> literalBooleanFunctionsPairs)
throws ParserException, TheoryException {
if (null == literalBooleanFunctionsPairs || literalBooleanFunctionsPairs.size() == 0) return;
for (CtLiteralBooleanFunctionPair literalBooleanFunctionPair : literalBooleanFunctionsPairs) {
spindle.core.dom.LiteralVariable name = generateLiteralVariable(literalBooleanFunctionPair.getName());
String literalFunctionStr = DflTheoryParser2.getLiteralFunctionEvaluationString(literalBooleanFunctionPair.getValue().trim(),
null, null);
spindle.core.dom.Literal vl = DomUtilities.getLiteral(literalFunctionStr, false);
spindle.core.dom.LiteralVariable value = DomUtilities.getLiteralVariable(vl);
theory.addLiteralVariable(name, value);
}
}
private spindle.core.dom.LiteralVariable generateLiteralVariable(CtLiteralVariable cLiteralVariable) throws ParserException {
String name = cLiteralVariable.getAtom();
spindle.core.dom.Literal literal = DomUtilities.getLiteral(name, false);
String[] predicates = generatePredicates(cLiteralVariable.getPredicates());
if (null != predicates) literal.setPredicates(predicates);
return DomUtilities.getLiteralVariable(literal);
}
private spindle.core.dom.Literal generateLiteral(CtLiteral cLiteral) throws ParserException {
String name = cLiteral.getAtom();
boolean isNegation = false;
String modeName = cLiteral.getMode();
boolean isModeNegation = false;
List<CtLiteral.Not> cNegations = cLiteral.getNot();
for (CtLiteral.Not cNegation : cNegations) {
if (null != cNegation.getAtom()) {
if (null != name) throw new ParserException("multiplue literal names are declared: " + name);
name = cNegation.getAtom();
isNegation = true;
} else if (null != cNegation.getMode()) {
if (null != modeName) throw new ParserException("multiplue literal modal operator are declared: " + modeName);
modeName = cNegation.getMode();
isModeNegation = true;
}
}
spindle.core.dom.Literal literal = DomUtilities.getLiteral(name, isNegation, modeName, isModeNegation);
CtInterval temporal = cLiteral.getInterval();
if (null != temporal) literal.setTemporal(generateTemporal(temporal));
String[] predicates = generatePredicates(cLiteral.getPredicates());
if (null != predicates) literal.setPredicates(predicates);
return literal;
}
private String[] generatePredicates(CtPredicates cPredicates) {
if (null != cPredicates) {
List<String> predicates = cPredicates.getPredicate();
if (predicates.size() == 0) return null;
String[] p = new String[predicates.size()];
predicates.toArray(p);
return p;
}
return null;
}
private spindle.core.dom.Temporal generateTemporal(CtInterval interval) {
long start = null == interval.getStart() ? Long.MIN_VALUE : interval.getStart();
long end = null == interval.getEnd() ? Long.MAX_VALUE : interval.getEnd();
return new spindle.core.dom.Temporal(start, end);
}
}