001 // This file is part of the Attempto Java Packages.
002 // Copyright 2008, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch).
003 //
004 // The Attempto Java Packages is free software: you can redistribute it and/or modify it under the
005 // terms of the GNU Lesser General Public License as published by the Free Software Foundation,
006 // either version 3 of the License, or (at your option) any later version.
007 //
008 // The Attempto Java Packages is distributed in the hope that it will be useful, but WITHOUT ANY
009 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
010 // PURPOSE. See the GNU Lesser General Public License for more details.
011 //
012 // You should have received a copy of the GNU Lesser General Public License along with the Attempto
013 // Java Packages. If not, see http://www.gnu.org/licenses/.
014
015 package ch.uzh.ifi.attempto.ape;
016
017 import jpl.Atom;
018 import jpl.Compound;
019 import jpl.JPL;
020 import jpl.Query;
021 import jpl.Term;
022 import jpl.Util;
023 import jpl.Variable;
024
025 /**
026 * This class provides an interface to the SWI Prolog executable of the Attempto Parsing Engine (APE).
027 * Note that you need the file "ape.exe" (which can be compiled from the Attempto APE distribution) and that
028 * SWI Prolog needs to be installed.
029 * Furthermore, you have to make sure that the JPL libraries of SWI Prolog are in the java library path.
030 * This can be achieved by a Java VM argument which looks like this (for Mac OS X):
031 *
032 * <blockquote><code>-Djava.library.path=/opt/local/lib/swipl-5.6.45/lib/i386-darwin8.10.1</code></blockquote>
033 *
034 * It is very likely that the path is different on your machine. Just look for the directory that contains
035 * the file or symbolic link <em>libjpl.jnilib</em> (under Mac OS X), <em>libjpl.dll</em> (under Windows), or
036 * <em>libjpl.so</em> (under Unix).
037 *
038 * If you get the error message
039 *
040 * <blockquote><code>java.lang.UnsatisfiedLinkError: no jpl in java.library.path</code></blockquote>
041 *
042 * then this is a strong indication that the SWI Prolog JPL libraries are not found.
043 *
044 *
045 * @author Tobias Kuhn
046 */
047 public class APELocal extends ACEParser {
048
049 private static APELocal apeLocal;
050
051 /**
052 * Creates a new parser object. You can create at most one such object per JVM. If you
053 * try to create more than one such object or if you called the init method before
054 * then a runtime exception is thrown.
055 *
056 * @param prologCommand The command to run the SWI Prolog interpreter.
057 * On Windows this is usually "plcon", on Linux "pl", and on Mac "swipl".
058 * @param apeExeFile The path (with filename) of the file "ape.exe".
059 */
060 public APELocal(String prologCommand, String apeExeFile) {
061 if (apeLocal != null) {
062 throw new RuntimeException("Only one APELocal object can be created.");
063 }
064 JPL.init(new String[] {prologCommand, "-x", apeExeFile, "-g", "true", "--nosignals"});
065 // A problem was reported that might be solved by using the --nosignals option.
066 // Otherwise, it seems to have no effect in our case.
067 apeLocal = this;
068 }
069
070 /**
071 * Returns the singleton APELocal instance. Null is returned if the APELocal instance has not yet
072 * been initialized by the constructor or the init method.
073 *
074 * @return The singleton APELocal instance.
075 */
076 public static APELocal getInstance() {
077 return apeLocal;
078 }
079
080 /**
081 * Initializes the APELocal singleton instance. This method can be called at most once.
082 * If you call it twice or if you called the constructor before then a runtime exception
083 * is thrown.
084 *
085 * @param prologCommand The command to run the SWI Prolog interpreter.
086 * On Windows this is usually "plcon", on Linux "pl", and on Mac "swipl".
087 * @param apeExeFile The path (with filename) of the file "ape.exe".
088 */
089 public static void init(String prologCommand, String apeExeFile) {
090 new APELocal(prologCommand, apeExeFile);
091 }
092
093 /**
094 * Checks whether the singleton instance has already been initialized.
095 *
096 * @return true if the singleton instance has been initialized.
097 */
098 public static boolean isInitialized() {
099 return apeLocal != null;
100 }
101
102 public synchronized String getSoloOutput(String text, Lexicon lexicon, OutputType outputType) throws ACEParserException {
103 clearMessages();
104 String ulextext = "";
105 if (lexicon != null) {
106 ulextext = ",ulextext=" + PrologUtils.escape(lexicon.toString());
107 }
108 Term input = Util.textToTerm("[text=" + PrologUtils.escape(text) + ulextext + ",solo=" + outputType.toString().toLowerCase() + getOptions() + "]");
109 Query q = new Query("get_ape_results", new Term[] {input, new Variable("Result")});
110 Atom result = (Atom) q.oneSolution().get("Result");
111 String s = result.name();
112
113 return checkForErrors(s);
114 }
115
116 public synchronized ACEParserResult getMultiOutput(String text, Lexicon lexicon, OutputType... outputTypes) {
117 clearMessages();
118 String outputs = "";
119 for (OutputType t : outputTypes) {
120 outputs += ",c" + t.toString().toLowerCase() + "=on";
121 }
122 String ulextext = "";
123 if (lexicon != null) {
124 ulextext = ",ulextext=" + PrologUtils.escape(lexicon.toString());
125 }
126 Term input = Util.textToTerm("[text=" + PrologUtils.escape(text) + ulextext + outputs + getOptions() + "]");
127 Query q = new Query("get_ape_results", new Term[] {input, new Variable("Result")});
128 Atom result = (Atom) q.oneSolution().get("Result");
129 return new ACEParserResult(result.name());
130 }
131
132 /**
133 * Loads the lexicon by adding all lexicon entries of the lexicon. Note that these lexicon entries
134 * are automatically discarded the first time you call getSoloOutput or getMultiOutput with a lexicon
135 * parameter that is not null.
136 *
137 * @param lexicon The lexicon to be loaded.
138 * @see #addLexiconEntry
139 * @see #discardLexicon
140 */
141 public synchronized void addLexicon(Lexicon lexicon) {
142 clearMessages();
143 Query q = new Query(new Compound("add_lexicon_entries", new Term[] { Util.textToTerm(lexicon.toList()) }));
144 q.oneSolution();
145 }
146
147 /**
148 * Adds a new lexicon entry. Note that this lexicon entry is automatically discarded the first time
149 * you call getSoloOutput or getMultiOutput with a lexicon parameter that is not null.
150 *
151 * @param lexiconEntry The lexicon entry to be added.
152 * @see #addLexicon
153 * @see #discardLexicon
154 */
155 public synchronized void addLexiconEntry(LexiconEntry lexiconEntry) {
156 clearMessages();
157 Query q = new Query(new Compound("add_lexicon_entry", new Term[] { Util.textToTerm(lexiconEntry.toString()) }) );
158 q.oneSolution();
159 }
160
161 /**
162 * Discards the dynamically added lexicon entries. Note that the lexicon entries that are complied into
163 * the SWI Prolog executable are not affected by this operation.
164 *
165 * @see #addLexiconEntry
166 * @see #addLexicon
167 */
168 public synchronized void discardLexicon() {
169 clearMessages();
170 Query q = new Query("discard_ulex");
171 q.oneSolution();
172 }
173
174 private void clearMessages() {
175 Query q = new Query("clear_messages");
176 q.oneSolution();
177 }
178 }