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>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    }