/** * 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); } }