001: package org.mandarax.xkb.ruleml;
002:
003: /*
004: * Copyright (C) 1999-2004 <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</a>
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020:
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Vector;
024:
025: import org.jdom.Comment;
026: import org.jdom.Document;
027: import org.jdom.Element;
028: import org.mandarax.kernel.ConstantTerm;
029: import org.mandarax.kernel.Fact;
030: import org.mandarax.kernel.KnowledgeBase;
031: import org.mandarax.kernel.Predicate;
032: import org.mandarax.kernel.Rule;
033: import org.mandarax.kernel.SimplePredicate;
034: import org.mandarax.kernel.Term;
035: import org.mandarax.kernel.VariableTerm;
036: import org.mandarax.xkb.AbstractXKBDriver;
037: import org.mandarax.xkb.XKBException;
038:
039: /**
040: * Abstract superclass for ruleml drivers.
041: * @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
042: * @version 3.4 <7 March 05>
043: * @since 1.9
044: */
045: abstract class AbstractRuleMLDriver extends AbstractXKBDriver {
046:
047: // constants for tags and attributes
048: public static final String IND = "ind";
049: public static final String VAR = "var";
050: public static final String _OPR = "_opr";
051: public static final String REL = "rel";
052: public static final String IMP = "imp";
053: public static final String FACT = "fact";
054: public static final String _HEAD = "_head";
055: public static final String _BODY = "_body";
056: public static final String ATOM = "atom";
057: public static final String AND = "and";
058: public static final String RULEBASE = "rulebase";
059:
060: /**
061: * Constructor.
062: */
063: public AbstractRuleMLDriver() {
064: super ();
065: }
066:
067: /**
068: * Export a constant term, e.g. convert it into an xml element.
069: * @return an element (of the jdom tree)
070: * @param ct a constant term
071: */
072: protected Element export(ConstantTerm ct) {
073: return exportJavaObject(ct.getObject());
074: }
075:
076: /**
077: * Export aan object
078: * @return an element (of the jdom tree)
079: * @param obj an arbirtary object
080: */
081: protected Element exportJavaObject(Object obj) {
082: Element e = new Element(IND);
083: e.addContent(obj == null ? "null" : obj.toString());
084: return e;
085: }
086:
087: /**
088: * Export a fact, e.g. convert it into an xml element.
089: * @return an element (of the jdom tree)
090: * @param f a fact
091: */
092: protected Element export(Fact f) {
093: Element e = new Element(FACT);
094: e.addContent(exportFact2Head(f));
095: return e;
096: }
097:
098: /**
099: * Export a knowledge base, e.g. convert it into an xml element.
100: * @return an element (of the jdom tree)
101: * @param kb a knowledge base
102: */
103: protected abstract Element export(KnowledgeBase kb);
104:
105: /**
106: * Export a predicate, e.g. convert it into an xml element.
107: * @return an element (of the jdom tree)
108: * @param p a predicate
109: */
110: protected Element export(Predicate p) {
111: Element e1 = new Element(_OPR);
112: Element e2 = new Element(REL);
113:
114: e2.addContent(p.getName());
115: e1.addContent(e2);
116:
117: return e1;
118: }
119:
120: /**
121: * Export a rule, e.g. convert it into an xml element.
122: * @return an element (of the jdom tree)
123: * @param r a rule
124: */
125: protected Element export(Rule r) {
126: Element e1 = new Element(IMP);
127: e1.addContent(exportFact2Head(r.getHead()));
128: Element e2 = new Element(_BODY);
129: Element e3 = new Element(AND);
130: Fact next = null;
131: List body = r.getBody();
132: for (Iterator it = body.iterator(); it.hasNext();) {
133: next = (Fact) it.next();
134: e3.addContent(exportFact2Atom(next));
135: }
136: e2.addContent(e3);
137: e1.addContent(e2);
138: return e1;
139: }
140:
141: /**
142: * Export a variable term, e.g. convert it into an xml element.
143: * @return an element (of the jdom tree)
144: * @param v a variable term
145: */
146: protected Element export(VariableTerm v) {
147: Element e = new Element(VAR);
148: e.addContent(v.getName());
149: return e;
150: }
151:
152: /**
153: * Export a fact, e.g. convert it into an xml element.
154: * @return an element (of the jdom tree)
155: * @param f a fact
156: */
157: protected Element exportFact2Atom(Fact f) {
158: Element e = new Element(ATOM);
159: e.addContent(export(f.getPredicate()));
160: Term[] terms = f.getTerms();
161: for (int i = 0; i < terms.length; i++) {
162: if (terms[i] instanceof ConstantTerm) {
163: e.addContent(export((ConstantTerm) terms[i]));
164: } else {
165: if (terms[i] instanceof VariableTerm) {
166: e.addContent(export((VariableTerm) terms[i]));
167: } else {
168: LOG_XKB
169: .warn("Only variable and constant terms are supported by driver "
170: + getName()
171: + ", cannot export "
172: + terms[i]);
173: }
174: }
175: }
176:
177: return e;
178: }
179:
180: /**
181: * Export a fact, e.g. convert it into an xml element.
182: * @return an element (of the jdom tree)
183: * @param f a fact
184: */
185: protected Element exportFact2Head(Fact f) {
186: Element e = new Element(_HEAD);
187: e.addContent(exportFact2Atom(f));
188: return e;
189: }
190:
191: /**
192: * Export a knowledge base, i.e., convert it into an xml document.
193: * @return an xml document
194: * @param kb a knowledge base
195: * @throws an XKBException is thrown if export fails
196: */
197: public Document exportKnowledgeBase(KnowledgeBase kb)
198: throws XKBException {
199: Document doc = new Document(export(kb));
200: Comment comm = new Comment("Export driver used: "
201: + this .getClass().getName());
202: doc.addContent(comm);
203: return doc;
204: }
205:
206: /**
207: * Get a short text describing the driver.
208: * @return a text
209: */
210: public String getDescription() {
211: return "Driver for rulebases as specified by the RULE ML version 0.8 specification";
212: }
213:
214: /**
215: * Import a fact list connected by "AND".
216: * @return a list
217: * @param e an xml element
218: * @throws an XKBException is thrown if import fails
219: */
220: private List importAnd(Element e) throws XKBException {
221: List children = e.getChildren(ATOM);
222: List premisses = new Vector(children.size());
223: for (Iterator it = children.iterator(); it.hasNext();) {
224: premisses.add(importAtom((Element) it.next()));
225: }
226: return premisses;
227: }
228:
229: /**
230: * Import an atom.
231: * @return a fact
232: * @param e an xml element
233: * @throws an XKBException is thrown if import fails
234: */
235: protected Fact importAtom(Element e) throws XKBException {
236: // predicate
237: Element ePredicate = e.getChild(_OPR);
238: if (ePredicate == null)
239: throw new XKBException("No child <_OPR> found in atom " + e
240: + ", cannot build predicate");
241: Predicate p = importPredicate(ePredicate);
242: // terms
243: List eTerms = collectChildren(e, IND, VAR);
244: Term[] terms = new Term[eTerms.size()];
245: for (int i = 0; i < terms.length; i++) {
246: terms[i] = importTerm((Element) eTerms.get(i));
247: }
248: // build and return fact
249: return lfactory.createFact(p, terms);
250: }
251:
252: /**
253: * Import a body.
254: * @return a list
255: * @param e an xml element
256: * @throws an XKBException is thrown if import fails
257: */
258: protected List importBody(Element e) throws XKBException {
259: Element eAnd = e.getChild(AND);
260:
261: if (eAnd == null) {
262: Element eAtom = e.getChild(ATOM);
263:
264: if (eAtom == null) {
265: LOG_XKB.warn("Body contains neither and nor atom");
266: return new Vector();
267: } else {
268: List body = new Vector(5);
269: body.add(importAtom(eAtom));
270: return body;
271: }
272: } else {
273: return importAnd(eAnd);
274: }
275: }
276:
277: /**
278: * Import a constant term.
279: * @return a constant term
280: * @param e an xml element
281: * @throws an XKBException is thrown if import fails
282: */
283: protected ConstantTerm importConstantTerm(Element e)
284: throws XKBException {
285: return lfactory.createConstantTerm(importJavaObject(e));
286: }
287:
288: /**
289: * Import a java object.
290: * @return a constant term
291: * @param e an xml element
292: * @throws an XKBException is thrown if import fails
293: */
294: protected Object importJavaObject(Element e) throws XKBException {
295: // warning: since RULE ML does not support typing, we use a fixed type String !
296: return e.getText();
297: }
298:
299: /**
300: * Import a fact.
301: * @return a fact
302: * @param e an xml element
303: * @throws an XKBException is thrown if import fails
304: */
305: protected Fact importFact(Element e) throws XKBException {
306: Element eHead = e.getChild(_HEAD);
307: if (eHead == null) {
308: throw new XKBException("Fact element contains no head");
309: }
310: return importHead(eHead);
311: }
312:
313: /**
314: * Import a head.
315: * @return a fact
316: * @param e an xml element
317: * @throws an XKBException is thrown if import fails
318: */
319: protected Fact importHead(Element e) throws XKBException {
320: Element eAtom = e.getChild(ATOM);
321: if (eAtom == null) {
322: throw new XKBException("Head element contains no atom");
323: }
324: return importAtom(eAtom);
325: }
326:
327: /**
328: * Import a knowledge base, i.e., build it from an xml document.
329: * @return a knowledge base
330: * @param doc an xml document
331: * @throws an XKBException is thrown if import fails
332: */
333: public KnowledgeBase importKnowledgeBase(Document doc)
334: throws XKBException {
335: Element root = doc.getRootElement();
336: if (compare(root.getName(), RULEBASE)) {
337: return importKnowledgeBase(root);
338: } else {
339: throw new XKBException(
340: "No rulebase root element found in xml source");
341: }
342: }
343:
344: /**
345: * Import a knowledge base.
346: * @return a knowledge base
347: * @param e an xml element
348: * @throws an XKBException is thrown if import fails
349: */
350: protected abstract KnowledgeBase importKnowledgeBase(Element e)
351: throws XKBException;
352:
353: /**
354: * Import a predicate.
355: * @return a predicate
356: * @param e an xml element
357: * @throws an XKBException is thrown if import fails
358: */
359: protected Predicate importPredicate(Element e) throws XKBException {
360:
361: // first figure out the number of root nodes of the parent
362: Element parent = (Element) e.getParent();
363: if (parent == null) {
364: LOG_XKB
365: .warn("Parent node of element representing a predicate is null, assume that there are no terms");
366: }
367: int termNumber = (parent == null) ? 0 : countChildren(parent,
368: IND, VAR);
369:
370: // figure out the name of the predicate, the name is the text in the
371: // <rel> tag
372: Element erel = e.getChild(REL);
373: if (erel == null) {
374: throw new XKBException(
375: "No <rel> tag found inside the <_op> tag, cannot built predicate");
376: }
377: // build simple predicate
378: Class[] types = new Class[termNumber];
379: for (int i = 0; i < termNumber; i++) {
380: types[i] = String.class;
381: }
382: return new SimplePredicate(erel.getText(), types);
383: }
384:
385: /**
386: * Import a rule.
387: * @return a rule
388: * @param e an xml element
389: * @throws an XKBException is thrown if import fails
390: */
391: protected Rule importRule(Element e) throws XKBException {
392: Element eHead = e.getChild(_HEAD);
393: Element eBody = e.getChild(_BODY);
394: Fact head = null;
395: List body = null;
396: if (eHead == null) {
397: throw new XKBException("Head of the rule cannot be empty");
398: }
399: head = importHead(eHead);
400: if (eBody == null) {
401: LOG_XKB.debug("No body tag found, assume body is empty");
402: body = new Vector();
403: } else {
404: body = importBody(eBody);
405: }
406: // build and return rule
407: return lfactory.createRule(body, head);
408: }
409:
410: /**
411: * Import a term.
412: * @return a term
413: * @param e an xml element
414: * @throws an XKBException is thrown if import fails
415: */
416: protected Term importTerm(Element e) throws XKBException {
417: if (compare(e.getName(), IND)) {
418: return importConstantTerm(e);
419: }
420: if (compare(e.getName(), VAR)) {
421: return importVariableTerm(e);
422: }
423: throw new XKBException(
424: "Only constants and variable terms can e imported by driver "
425: + getName());
426: }
427:
428: /**
429: * Import a variable term.
430: * @return a variable term
431: * @param e an xml element
432: * @throws an XKBException is thrown if import fails
433: */
434: private VariableTerm importVariableTerm(Element e)
435: throws XKBException {
436:
437: // warning: since RULE ML does not support typing, we use a fixed type String !
438: String value = e.getText();
439:
440: return lfactory.createVariableTerm(value, String.class);
441: }
442:
443: }
|