001    // This file is part of AceWiki.
002    // Copyright 2008-2012, AceWiki developers.
003    //
004    // AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU
005    // Lesser General Public License as published by the Free Software Foundation, either version 3 of
006    // the License, or (at your option) any later version.
007    //
008    // AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009    // even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
010    // Lesser General Public License for more details.
011    //
012    // You should have received a copy of the GNU Lesser General Public License along with AceWiki. If
013    // not, see http://www.gnu.org/licenses/.
014    
015    package ch.uzh.ifi.attempto.acewiki.aceowl;
016    
017    import static ch.uzh.ifi.attempto.ape.OutputType.DRSPP;
018    import static ch.uzh.ifi.attempto.ape.OutputType.OWLFSSPP;
019    import static ch.uzh.ifi.attempto.ape.OutputType.OWLXML;
020    import static ch.uzh.ifi.attempto.ape.OutputType.PARAPHRASE1;
021    import static ch.uzh.ifi.attempto.ape.OutputType.SYNTAX;
022    import static ch.uzh.ifi.attempto.ape.OutputType.SYNTAXPP;
023    
024    import java.util.ArrayList;
025    import java.util.Arrays;
026    import java.util.HashSet;
027    import java.util.List;
028    import java.util.Set;
029    
030    import org.apache.commons.lang.StringEscapeUtils;
031    import org.semanticweb.owlapi.apibinding.OWLManager;
032    import org.semanticweb.owlapi.io.StringDocumentSource;
033    import org.semanticweb.owlapi.model.OWLAxiom;
034    import org.semanticweb.owlapi.model.OWLOntology;
035    import org.semanticweb.owlapi.model.OWLOntologyCreationException;
036    import org.semanticweb.owlapi.model.OWLOntologyManager;
037    import org.semanticweb.owlapi.profiles.OWLProfile;
038    import org.semanticweb.owlapi.profiles.OWLProfileReport;
039    import org.semanticweb.owlapi.profiles.OWLProfileViolation;
040    
041    import ch.uzh.ifi.attempto.acewiki.core.Declaration;
042    import ch.uzh.ifi.attempto.acewiki.core.MonolingualSentence;
043    import ch.uzh.ifi.attempto.acewiki.core.OntologyElement;
044    import ch.uzh.ifi.attempto.acewiki.core.OntologyTextElement;
045    import ch.uzh.ifi.attempto.acewiki.core.SentenceDetail;
046    import ch.uzh.ifi.attempto.acewiki.owl.AceWikiOWLReasoner;
047    import ch.uzh.ifi.attempto.acewiki.owl.OWLSentence;
048    import ch.uzh.ifi.attempto.ape.ACEParser;
049    import ch.uzh.ifi.attempto.ape.ACEParserResult;
050    import ch.uzh.ifi.attempto.ape.Lexicon;
051    import ch.uzh.ifi.attempto.ape.LexiconEntry;
052    import ch.uzh.ifi.attempto.ape.MessageContainer;
053    import ch.uzh.ifi.attempto.ape.SyntaxBoxes;
054    import ch.uzh.ifi.attempto.base.APE;
055    import ch.uzh.ifi.attempto.base.TextContainer;
056    import ch.uzh.ifi.attempto.base.TextElement;
057    
058    /**
059     * This class represents an ACE sentence, which can be either a declarative sentence or a question.
060     *
061     * @author Tobias Kuhn
062     */
063    public abstract class ACESentence extends MonolingualSentence implements OWLSentence {
064    
065            private static OWLOntologyManager ontologyManager = OWLManager.createOWLOntologyManager();
066    
067            // This field is either initialized when the object is created, or otherwise unused:
068            private String serialized;
069    
070            // Unless initialized when the object is created, this field is evaluated lazily:
071            private TextContainer textContainer;
072    
073            // These fields are evaluated lazily:
074            private ACEParserResult parserResult;
075            private Boolean reasonable;
076            private Boolean isOWL;
077            private Boolean isOWLSWRL;
078            private Set<OWLAxiom> owlAxioms;
079    
080            /**
081             * Initializes a new ACE sentence.
082             *
083             * @param serialized The serialized representation of the sentence.
084             */
085            protected ACESentence(String serialized) {
086                    this.serialized = serialized;
087            }
088    
089            /**
090             * Initializes a new ACE sentence.
091             *
092             * @param textContainer The text container with the sentence text.
093             */
094            protected ACESentence(TextContainer textContainer) {
095                    this.textContainer = textContainer;
096            }
097    
098            public List<TextElement> getTextElements() {
099                    List<TextElement> list = new ArrayList<TextElement>();
100                    // TODO: this should be done in a different way
101                    for (TextElement e : getTextContainer().getTextElements()) {
102                            if (e instanceof OntologyTextElement) {
103                                    OntologyTextElement ote = (OntologyTextElement) e;
104                                    OntologyElement oe = ote.getOntologyElement();
105                                    if (ote.getPreText().length() > 0) {
106                                            list.add(new TextElement(ote.getPreText()));
107                                            ote = new OntologyTextElement(oe, ote.getWordNumber());
108                                    }
109                                    if (oe instanceof ProperNameIndividual) {
110                                            // Proper names with definite articles are handled differently: The "the" is
111                                            // not a part of the link.
112                                            ProperNameIndividual ind = (ProperNameIndividual) oe;
113                                            int wn = ote.getWordNumber();
114                                            if (ind.hasDefiniteArticle(wn)) {
115                                                    list.add(new TextElement(e.getText().substring(0, 3)));
116                                                    list.add(new OntologyTextElement(ind, wn+1));
117                                            } else {
118                                                    list.add(ote);
119                                            }
120                                    } else {
121                                            list.add(ote);
122                                    }
123                            } else {
124                                    list.add(e);
125                            }
126                    }
127                    return list;
128            }
129    
130            protected TextContainer getTextContainer() {
131                    if (textContainer == null) {
132                            tokenize();
133                    }
134                    return textContainer;
135            }
136    
137            private void tokenize() {
138                    textContainer = new TextContainer(getTextOperator());
139    
140                    // TODO Remove legacy code at some point
141    
142                    // Replace for legacy code below:
143                    //List<String> tokens = Arrays.asList(serialized.split(" "));
144    
145                    // This is legacy code to support old acewikidata files:
146                    String t = "&" + serialized + "&";
147                    t = t.replaceAll(" ", "&");
148                    t = t.replaceAll("\\.", "&.&");
149                    t = t.replaceAll("\\?", "&?&");
150                    t = t.replaceAll("&of&", " of&");
151                    t = t.replaceAll("&by&", " by&");
152    
153                    List<String> tokens = new ArrayList<String>(Arrays.asList(t.split("&")));
154    
155                    while (tokens.contains("")) {
156                            tokens.remove("");
157                    }
158                    // End of legacy code
159    
160                    for (String s : tokens) {
161                            if (s.startsWith("<")) {
162                                    OntologyTextElement te;
163                                    try {
164                                            long oeId = new Long(s.substring(1, s.indexOf(",")));
165                                            int wordNumber = new Integer(s.substring(s.indexOf(",")+1, s.indexOf(">")));
166                                            OntologyElement oe = getOntology().get(oeId);
167                                            te = new OntologyTextElement(oe, wordNumber);
168                                    } catch (Exception ex) {
169                                            throw new RuntimeException("Could not resolve link: " + s, ex);
170                                    }
171                                    textContainer.addElement(te);
172                            } else {
173                                    TextElement te = getTextOperator().createTextElement(s);
174                                    if (!(te instanceof OntologyTextElement) || serialized.indexOf("<") > -1) {
175                                            textContainer.addElement(te);
176                                    } else {
177                                            // This is legacy code to support old acewikidata files:
178                                            OntologyTextElement ote = (OntologyTextElement) te;
179                                            OntologyElement oe = ote.getOntologyElement();
180                                            int wordId = ote.getWordNumber();
181                                            if (oe instanceof ProperNameIndividual) {
182                                                    ProperNameIndividual ind = (ProperNameIndividual) oe;
183                                                    if (ind.hasDefiniteArticle(wordId-1) && textContainer.getTextElementsCount() > 0) {
184                                                            String precedingText = textContainer.
185                                                            getTextElement(textContainer.getTextElementsCount()-1).
186                                                            getText();
187                                                            if (precedingText.equals("the") || precedingText.equals("The")) {
188                                                                    textContainer.removeLastElement();
189                                                                    wordId--;
190                                                            }
191                                                    }
192                                            }
193                                            textContainer.addElement(new OntologyTextElement(oe, wordId));
194                                            // End of legacy code
195                                    }
196                            }
197                    }
198            }
199    
200            /**
201             * Returns the parser result object.
202             *
203             * @return The parser result object.
204             */
205            public ACEParserResult getParserResult() {
206                    if (parserResult == null) {
207                            update();
208                    }
209                    return parserResult;
210            }
211    
212            public String getPrettyOWL() {
213                    if (parserResult == null) {
214                            update();
215                    }
216                    return parserResult.get(OWLFSSPP);
217            }
218    
219            public boolean isReasonable() {
220                    if (reasonable == null) {
221                            update();
222                    }
223                    return reasonable;
224            }
225    
226            public boolean isOWL() {
227                    if (isOWL == null) {
228                            update();
229                    }
230                    return isOWL;
231            }
232    
233            public boolean isOWLSWRL() {
234                    if (isOWLSWRL == null) {
235                            update();
236                    }
237                    return isOWLSWRL;
238            }
239    
240            public Set<OWLAxiom> getOWLAxioms() {
241                    if (parserResult == null) {
242                            update();
243                    }
244                    if (owlAxioms == null) {
245                            owlAxioms = new HashSet<OWLAxiom>();
246                    }
247                    return owlAxioms;
248            }
249    
250            public void update() {
251                    // TODO: refactor and clean-up!
252                    AceWikiOWLReasoner reasoner = (AceWikiOWLReasoner) getOntology()
253                                    .getReasoner().getWrappedReasoner();
254    
255                    ACEParser ape = APE.getParser();
256                    synchronized (ape) {
257                            ape.setURI(getOntology().getURI());
258                            ape.setClexEnabled(false);
259                            Lexicon lexicon = new Lexicon();
260                            for (TextElement te : getTextContainer().getTextElements()) {
261                                    if (te instanceof OntologyTextElement) {
262                                            OntologyElement oe = ((OntologyTextElement) te).getOntologyElement();
263                                            if (oe instanceof ACEOWLOntoElement) {
264                                                    for (LexiconEntry le : ((ACEOWLOntoElement) oe).getLexiconEntries()) {
265                                                            lexicon.addEntry(le);
266                                                    }
267                                            }
268                                    }
269                            }
270                            parserResult = ape.getMultiOutput(
271                                            getText(),
272                                            lexicon,
273                                            PARAPHRASE1,
274                                            SYNTAX,
275                                            SYNTAXPP,
276                                            OWLXML,
277                                            OWLFSSPP,
278                                            DRSPP
279                                    );
280                    }
281                    MessageContainer mc = parserResult.getMessageContainer();
282                    String owlxml = parserResult.get(OWLXML);
283    
284                    isOWLSWRL =
285                            (mc.getMessages("owl").size() == 0) &&
286                            (owlxml.length() > 0);
287    
288                    isOWL = isOWLSWRL &&
289                            (owlxml.indexOf("<swrl:Imp>") < 0) &&
290                            (owlxml.indexOf("<DLSafeRule>") < 0);
291    
292                    if (isOWL && reasoner.getGlobalRestrictionsPolicy().equals("no_chains")) {
293                            reasonable =
294                                    (owlxml.indexOf("<TransitiveObjectProperty>") < 0) &&
295                                    (owlxml.indexOf("<ObjectPropertyChain>") < 0);
296                    } else {
297                            reasonable = isOWL;
298                    }
299    
300                    owlAxioms = null;
301                    OWLOntology owlOntology = null;
302                    if (isOWL) {
303                            try {
304                                    owlOntology = ontologyManager.loadOntologyFromOntologyDocument(
305                                                    new StringDocumentSource(owlxml)
306                                            );
307                                    if (owlOntology.isEmpty()) {
308                                            reasonable = false;
309                                            isOWL = false;
310                                            isOWLSWRL = false;
311                                    } else {
312                                            owlAxioms = owlOntology.getAxioms();
313                                    }
314                            } catch (OWLOntologyCreationException ex) {
315                                    ex.printStackTrace();
316                            }
317                    }
318                    OWLProfile owlProfile = reasoner.getOWLProfile();
319                    if (reasonable && owlOntology != null && owlProfile != null && this instanceof Declaration) {
320                            OWLProfileReport r = owlProfile.checkOntology(owlOntology);
321                            for (OWLProfileViolation v : r.getViolations()) {
322                                    if (!v.toString().startsWith("Use of undeclared")) {
323                                            reasonable = false;
324                                            break;
325                                    }
326                            }
327                    }
328                    if (owlOntology != null) {
329                            ontologyManager.removeOntology(owlOntology);
330                    }
331                    if (!reasonable && isIntegrated()) {
332                            super.setIntegrated(false);
333                    }
334                    //String messages = mc.toString();
335                    //if (messages.length() > 0) {
336                    //      System.err.println("Parser messages: " + messages);
337                    //}
338            }
339    
340            public void setIntegrated(boolean integrated) {
341                    if (integrated && reasonable != null && !reasonable) {
342                            super.setIntegrated(false);
343                    } else {
344                            super.setIntegrated(integrated);
345                    }
346            }
347    
348            public boolean contains(OntologyElement e) {
349                    for (TextElement t : getTextContainer().getTextElements()) {
350                            if (t instanceof OntologyTextElement) {
351                                    if (e == ((OntologyTextElement) t).getOntologyElement()) return true;
352                            }
353                    }
354                    return false;
355            }
356    
357            public String serialize() {
358                    String s = "";
359                    for (TextElement te : getTextContainer().getTextElements()) {
360                            if (te instanceof OntologyTextElement) {
361                                    OntologyTextElement ot = (OntologyTextElement) te;
362                                    s += ot.getPreText();
363                                    s += "<" + ot.getOntologyElement().getId() + "," + ot.getWordNumber() + "> ";
364                                    s += ot.getPostText();
365                            } else {
366                                    s += te.getText() + " ";
367                            }
368                    }
369                    s = s.replaceAll(" $", "");
370                    return s;
371            }
372    
373            public List<SentenceDetail> getDetails() {
374                    List<SentenceDetail> l = new ArrayList<SentenceDetail>();
375                    l.add(new SentenceDetail(
376                                    "Paraphrase",
377                                    StringEscapeUtils.escapeHtml(getParserResult().get(PARAPHRASE1))
378                            ));
379                    l.add(new SentenceDetail(
380                                    "Syntax Boxes",
381                                    SyntaxBoxes.getBoxesHtml(getParserResult())
382                            ));
383                    l.add(new SentenceDetail(
384                                    "Syntax Tree",
385                                    "<pre>" + getParserResult().get(SYNTAXPP) + "</pre>"
386                            ));
387                    l.add(new SentenceDetail(
388                                    "Logical representation",
389                                    "<i><pre>" + StringEscapeUtils.escapeHtml(getParserResult().get(DRSPP)) + "</pre></i>"
390                            ));
391                    if (isOWLSWRL()) {
392                            l.add(new SentenceDetail(
393                                            "OWL",
394                                            "<i><pre>" + StringEscapeUtils.escapeHtml(getPrettyOWL()) + "</pre></i>"
395                                    ));
396                    }
397                    return l;
398            }
399    
400    }