001    //This file is part of the Attempto Java Packages.
002    //Copyright 2008-2009, 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>jpl.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 apeExeFile The path (with filename) of the file "ape.exe".
057             */
058            public APELocal(String apeExeFile) {
059                    // TODO: Clean up the "IGNORED" bit.
060                    this("IGNORED", apeExeFile);
061            }
062    
063            /**
064             * Creates a new parser object. You can create at most one such object per JVM. If you
065             * try to create more than one such object or if you called the init method before
066             * then a runtime exception is thrown.
067             * <br>
068             * This method is deprecated because the {@code prologCommand} argument is actually not needed.
069             * Use {@link #APELocal(String)} instead.
070             * 
071             * @param prologCommand The command to run the SWI Prolog interpreter.
072             *     On Windows this is usually "plcon", on Linux "pl", and on Mac "swipl".
073             * @param apeExeFile The path (with filename) of the file "ape.exe".
074             */
075            @Deprecated
076            public APELocal(String prologCommand, String apeExeFile) {
077                    if (apeLocal != null) {
078                            throw new RuntimeException("Only one APELocal object can be created.");
079                    }
080                    JPL.init(new String[] {prologCommand, "-x", apeExeFile, "-g", "true", "--nosignals"});
081                    // A problem was reported that might be solved by using the --nosignals option.
082                    // Otherwise, it seems to have no effect in our case.
083                    apeLocal = this;
084            }
085    
086            /**
087             * Returns the singleton APELocal instance. Null is returned if the APELocal instance has not yet
088             * been initialized by the constructor or the init method.
089             * 
090             * @return The singleton APELocal instance.
091             */
092            public static APELocal getInstance() {
093                    return apeLocal;
094            }
095    
096            /**
097             * Initializes the APELocal singleton instance. This method can be called at most once.
098             * If you call it twice or if you called the constructor before then a runtime exception
099             * is thrown.
100             * 
101             * @param apeExeFile The path (with filename) of the file "ape.exe".
102             */
103            public static void init(String apeExeFile) {
104                    // TODO: Clean up the "IGNORED" bit.
105                    new APELocal("IGNORED", apeExeFile);
106            }
107    
108            /**
109             * Initializes the APELocal singleton instance. This method can be called at most once.
110             * If you call it twice or if you called the constructor before then a runtime exception
111             * is thrown.
112             * <br>
113             * This method is deprecated because the {@code prologCommand} argument is actually not needed.
114             * Use {@link #init(String)} instead.
115             * 
116             * @param prologCommand The command to run the SWI Prolog interpreter.
117             *     On Windows this is usually "plcon", on Linux "pl", and on Mac "swipl".
118             * @param apeExeFile The path (with filename) of the file "ape.exe".
119             */
120            @Deprecated
121            public static void init(String prologCommand, String apeExeFile) {
122                    new APELocal(prologCommand, apeExeFile);
123            }
124    
125            /**
126             * Checks whether the singleton instance has already been initialized.
127             * 
128             * @return true if the singleton instance has been initialized.
129             */
130            public static boolean isInitialized() {
131                    return apeLocal != null;
132            }
133    
134            public synchronized String getSoloOutput(String text, Lexicon lexicon, OutputType outputType) throws ACEParserException {
135                    clearMessages();
136                    String ulextext = "";
137                    if (lexicon != null) {
138                            ulextext = ",ulextext=" + PrologUtils.escape(lexicon.toString());
139                    }
140                    Term input = Util.textToTerm("[text=" + PrologUtils.escape(text) + ulextext + ",solo=" + outputType.toString().toLowerCase() + getOptions() + "]");
141                    Query q = new Query("get_ape_results", new Term[] {input, new Variable("Result")});
142                    Atom result = (Atom) q.oneSolution().get("Result");
143                    String s = result.name();
144    
145                    return checkForErrors(s);
146            }
147    
148            public synchronized ACEParserResult getMultiOutput(String text, Lexicon lexicon, OutputType... outputTypes) {
149                    clearMessages();
150                    String outputs = "";
151                    for (OutputType t : outputTypes) {
152                            outputs += ",c" + t.toString().toLowerCase() + "=on";
153                    }
154                    String ulextext = "";
155                    if (lexicon != null) {
156                            ulextext = ",ulextext=" + PrologUtils.escape(lexicon.toString());
157                    }
158                    Term input = Util.textToTerm("[text=" + PrologUtils.escape(text) + ulextext + outputs + getOptions() + "]");
159                    Query q = new Query("get_ape_results", new Term[] {input, new Variable("Result")});
160                    Atom result = (Atom) q.oneSolution().get("Result");
161                    return new ACEParserResult(result.name());
162            }
163    
164            /**
165             * Loads the lexicon by adding all lexicon entries of the lexicon. Note that these lexicon entries
166             * are automatically discarded the first time you call getSoloOutput or getMultiOutput with a lexicon
167             * parameter that is not null.
168             * 
169             * @param lexicon The lexicon to be loaded.
170             * @see #addLexiconEntry
171             * @see #discardLexicon
172             */
173            public synchronized void addLexicon(Lexicon lexicon) {
174                    clearMessages();
175                    Query q = new Query(new Compound("add_lexicon_entries", new Term[] { Util.textToTerm(lexicon.toList()) }));
176                    q.oneSolution();
177            }
178    
179            /**
180             * Adds a new lexicon entry. Note that this lexicon entry is automatically discarded the first time
181             * you call getSoloOutput or getMultiOutput with a lexicon parameter that is not null.
182             * 
183             * @param lexiconEntry The lexicon entry to be added.
184             * @see #addLexicon
185             * @see #discardLexicon
186             */
187            public synchronized void addLexiconEntry(LexiconEntry lexiconEntry) {
188                    clearMessages();
189                    Query q = new Query(new Compound("add_lexicon_entry", new Term[] { Util.textToTerm(lexiconEntry.toString()) }) );
190                    q.oneSolution();
191            }
192    
193            /**
194             * Discards the dynamically added lexicon entries. Note that the lexicon entries that are complied into
195             * the SWI Prolog executable are not affected by this operation.
196             *
197             * @see #addLexiconEntry
198             * @see #addLexicon
199             */
200            public synchronized void discardLexicon() {
201                    clearMessages();
202                    Query q = new Query("discard_ulex");
203                    q.oneSolution();
204            }
205    
206            private void clearMessages() {
207                    Query q = new Query("clear_messages");
208                    q.oneSolution();
209            }
210    }