// This file is part of AceWiki.
// Copyright 2008-2013, AceWiki developers.
//
// AceWiki 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.
//
// AceWiki 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 AceWiki. If
// not, see http://www.gnu.org/licenses/.
package ch.uzh.ifi.attempto.acewiki.aceowl;
import static ch.uzh.ifi.attempto.ape.OutputType.DRSPP;
import static ch.uzh.ifi.attempto.ape.OutputType.OWLFSSPP;
import static ch.uzh.ifi.attempto.ape.OutputType.OWLXML;
import static ch.uzh.ifi.attempto.ape.OutputType.PARAPHRASE1;
import static ch.uzh.ifi.attempto.ape.OutputType.SYNTAX;
import static ch.uzh.ifi.attempto.ape.OutputType.SYNTAXPP;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringEscapeUtils;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.io.StringDocumentSource;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.profiles.OWLProfile;
import org.semanticweb.owlapi.profiles.OWLProfileReport;
import org.semanticweb.owlapi.profiles.OWLProfileViolation;
import ch.uzh.ifi.attempto.acewiki.core.Declaration;
import ch.uzh.ifi.attempto.acewiki.core.MonolingualSentence;
import ch.uzh.ifi.attempto.acewiki.core.OntologyElement;
import ch.uzh.ifi.attempto.acewiki.core.OntologyTextElement;
import ch.uzh.ifi.attempto.acewiki.core.SentenceDetail;
import ch.uzh.ifi.attempto.acewiki.owl.AceWikiOWLReasoner;
import ch.uzh.ifi.attempto.acewiki.owl.OWLSentence;
import ch.uzh.ifi.attempto.ape.ACEParser;
import ch.uzh.ifi.attempto.ape.ACEParserResult;
import ch.uzh.ifi.attempto.ape.Lexicon;
import ch.uzh.ifi.attempto.ape.LexiconEntry;
import ch.uzh.ifi.attempto.ape.MessageContainer;
import ch.uzh.ifi.attempto.ape.SyntaxBoxes;
import ch.uzh.ifi.attempto.base.APE;
import ch.uzh.ifi.attempto.base.MultiTextContainer;
import ch.uzh.ifi.attempto.base.TextContainer;
import ch.uzh.ifi.attempto.base.TextElement;
/**
* This class represents an ACE sentence, which can be either a declarative sentence or a question.
*
* @author Tobias Kuhn
*/
public abstract class ACESentence extends MonolingualSentence implements OWLSentence {
private static OWLOntologyManager ontologyManager = OWLManager.createOWLOntologyManager();
// This field is either initialized when the object is created, or otherwise unused:
private String serialized;
// Unless initialized when the object is created, this field is evaluated lazily:
private TextContainer textContainer;
// These fields are evaluated lazily:
private ACEParserResult parserResult;
private Boolean reasonable;
private Boolean isOWL;
private Boolean isOWLSWRL;
private Set<OWLAxiom> owlAxioms;
/**
* Initializes a new ACE sentence.
*
* @param serialized The serialized representation of the sentence.
*/
protected ACESentence(String serialized) {
this.serialized = serialized;
}
/**
* Initializes a new ACE sentence.
*
* @param textContainer The text container with the sentence text.
*/
protected ACESentence(TextContainer textContainer) {
this.textContainer = textContainer;
}
public List<TextElement> getTextElements() {
List<TextElement> list = new ArrayList<TextElement>();
// TODO: this should be done in a different way
for (TextElement e : getTextContainer().getTextElements()) {
if (e instanceof OntologyTextElement) {
OntologyTextElement ote = (OntologyTextElement) e;
OntologyElement oe = ote.getOntologyElement();
if (ote.getPreText().length() > 0) {
list.add(new TextElement(ote.getPreText()));
ote = new OntologyTextElement(oe, ote.getWordNumber());
}
if (oe instanceof ProperNameIndividual) {
// Proper names with definite articles are handled differently: The "the" is
// not a part of the link.
ProperNameIndividual ind = (ProperNameIndividual) oe;
int wn = ote.getWordNumber();
if (ind.hasDefiniteArticle(wn)) {
list.add(new TextElement(e.getText().substring(0, 3)));
list.add(new OntologyTextElement(ind, wn+1));
} else {
list.add(ote);
}
} else {
list.add(ote);
}
} else {
list.add(e);
}
}
return list;
}
public MultiTextContainer getTextContainer() {
if (textContainer == null) {
tokenize();
}
return new MultiTextContainer(textContainer);
}
private void tokenize() {
textContainer = new TextContainer(getTextOperator());
// TODO Remove legacy code at some point
// Replace for legacy code below:
//List<String> tokens = Arrays.asList(serialized.split(" "));
// This is legacy code to support old acewikidata files:
String t = "&" + serialized + "&";
t = t.replaceAll(" ", "&");
t = t.replaceAll("\\.", "&.&");
t = t.replaceAll("\\?", "&?&");
t = t.replaceAll("&of&", " of&");
t = t.replaceAll("&by&", " by&");
List<String> tokens = new ArrayList<String>(Arrays.asList(t.split("&")));
while (tokens.contains("")) {
tokens.remove("");
}
// End of legacy code
for (String s : tokens) {
if (s.startsWith("<")) {
OntologyTextElement te;
try {
long oeId = new Long(s.substring(1, s.indexOf(",")));
int wordNumber = new Integer(s.substring(s.indexOf(",")+1, s.indexOf(">")));
OntologyElement oe = getOntology().get(oeId);
te = new OntologyTextElement(oe, wordNumber);
} catch (Exception ex) {
throw new RuntimeException("Could not resolve link: " + s, ex);
}
textContainer.addElement(te);
} else {
TextElement te = getTextOperator().createTextElement(s);
if (!(te instanceof OntologyTextElement) || serialized.indexOf("<") > -1) {
textContainer.addElement(te);
} else {
// This is legacy code to support old acewikidata files:
OntologyTextElement ote = (OntologyTextElement) te;
OntologyElement oe = ote.getOntologyElement();
int wordId = ote.getWordNumber();
if (oe instanceof ProperNameIndividual) {
ProperNameIndividual ind = (ProperNameIndividual) oe;
if (ind.hasDefiniteArticle(wordId-1) && textContainer.getTextElementsCount() > 0) {
String precedingText = textContainer.
getTextElement(textContainer.getTextElementsCount()-1).
getText();
if (precedingText.equals("the") || precedingText.equals("The")) {
textContainer.removeLastElement();
wordId--;
}
}
}
textContainer.addElement(new OntologyTextElement(oe, wordId));
// End of legacy code
}
}
}
}
/**
* Returns the parser result object.
*
* @return The parser result object.
*/
public ACEParserResult getParserResult() {
if (parserResult == null) {
update();
}
return parserResult;
}
public String getPrettyOWL() {
if (parserResult == null) {
update();
}
return parserResult.get(OWLFSSPP);
}
public boolean isReasonable() {
if (reasonable == null) {
update();
}
return reasonable;
}
public boolean isOWL() {
if (isOWL == null) {
update();
}
return isOWL;
}
public boolean isOWLSWRL() {
if (isOWLSWRL == null) {
update();
}
return isOWLSWRL;
}
public Set<OWLAxiom> getOWLAxioms() {
if (parserResult == null) {
update();
}
if (owlAxioms == null) {
owlAxioms = new HashSet<OWLAxiom>();
}
return owlAxioms;
}
public void update() {
// TODO: refactor and clean-up!
AceWikiOWLReasoner reasoner = (AceWikiOWLReasoner) getOntology()
.getReasoner().getWrappedReasoner();
ACEParser ape = APE.getParser();
synchronized (ape) {
ape.setURI(getOntology().getURI());
ape.setClexEnabled(false);
Lexicon lexicon = new Lexicon();
for (TextElement te : getTextContainer().getTextElements()) {
if (te instanceof OntologyTextElement) {
OntologyElement oe = ((OntologyTextElement) te).getOntologyElement();
if (oe instanceof ACEOWLOntoElement) {
for (LexiconEntry le : ((ACEOWLOntoElement) oe).getLexiconEntries()) {
lexicon.addEntry(le);
}
}
}
}
parserResult = ape.getMultiOutput(
getText(),
lexicon,
PARAPHRASE1,
SYNTAX,
SYNTAXPP,
OWLXML,
OWLFSSPP,
DRSPP
);
}
MessageContainer mc = parserResult.getMessageContainer();
String owlxml = parserResult.get(OWLXML);
isOWLSWRL =
(mc.getMessages("owl").size() == 0) &&
(owlxml.length() > 0);
isOWL = isOWLSWRL &&
(owlxml.indexOf("<swrl:Imp>") < 0) &&
(owlxml.indexOf("<DLSafeRule>") < 0);
if (isOWL && reasoner.getGlobalRestrictionsPolicy().equals("no_chains")) {
reasonable =
(owlxml.indexOf("<TransitiveObjectProperty>") < 0) &&
(owlxml.indexOf("<ObjectPropertyChain>") < 0);
} else {
reasonable = isOWL;
}
owlAxioms = null;
OWLOntology owlOntology = null;
if (isOWL) {
try {
owlOntology = ontologyManager.loadOntologyFromOntologyDocument(
new StringDocumentSource(owlxml)
);
if (owlOntology.isEmpty()) {
reasonable = false;
isOWL = false;
isOWLSWRL = false;
} else {
owlAxioms = owlOntology.getAxioms();
}
} catch (OWLOntologyCreationException ex) {
ex.printStackTrace();
}
}
OWLProfile owlProfile = reasoner.getOWLProfile();
if (reasonable && owlOntology != null && owlProfile != null && this instanceof Declaration) {
OWLProfileReport r = owlProfile.checkOntology(owlOntology);
for (OWLProfileViolation v : r.getViolations()) {
if (!v.toString().startsWith("Use of undeclared")) {
reasonable = false;
break;
}
}
}
if (owlOntology != null) {
ontologyManager.removeOntology(owlOntology);
}
if (!reasonable && isIntegrated()) {
super.setIntegrated(false);
}
//String messages = mc.toString();
//if (messages.length() > 0) {
// final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(this.getClass());
// log.info(org.slf4j.MarkerFactory.getMarker("stderr"), "Parser messages: {}", messages);
//}
}
public void setIntegrated(boolean integrated) {
if (integrated && reasonable != null && !reasonable) {
super.setIntegrated(false);
} else {
super.setIntegrated(integrated);
}
}
public boolean contains(OntologyElement e) {
for (TextElement t : getTextContainer().getTextElements()) {
if (t instanceof OntologyTextElement) {
if (e == ((OntologyTextElement) t).getOntologyElement()) return true;
}
}
return false;
}
public String serialize() {
String s = "";
for (TextElement te : getTextContainer().getTextElements()) {
if (te instanceof OntologyTextElement) {
OntologyTextElement ot = (OntologyTextElement) te;
s += ot.getPreText();
s += "<" + ot.getOntologyElement().getId() + "," + ot.getWordNumber() + "> ";
s += ot.getPostText();
} else {
s += te.getText() + " ";
}
}
s = s.replaceAll(" $", "");
return s;
}
public List<SentenceDetail> getDetails() {
List<SentenceDetail> l = new ArrayList<SentenceDetail>();
l.add(new SentenceDetail(
"acewiki_details_paraphrase",
StringEscapeUtils.escapeHtml(getParserResult().get(PARAPHRASE1))
));
l.add(new SentenceDetail(
"Syntax Boxes",
SyntaxBoxes.getBoxesHtml(getParserResult())
));
l.add(new SentenceDetail(
"acewiki_details_syntree",
"<pre>" + getParserResult().get(SYNTAXPP) + "</pre>"
));
l.add(new SentenceDetail(
"acewiki_details_internal",
"<i><pre>" + StringEscapeUtils.escapeHtml(getParserResult().get(DRSPP)) + "</pre></i>"
));
if (isOWLSWRL()) {
l.add(new SentenceDetail(
"OWL",
"<i><pre>" + StringEscapeUtils.escapeHtml(getPrettyOWL()) + "</pre></i>"
));
}
return l;
}
}